@eusend_dev/sdk 0.18.0 → 0.19.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/README.md +25 -2
- package/dist/index.cjs +29 -6
- package/dist/index.d.cts +37 -9
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +37 -9
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +29 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -128,6 +128,12 @@ const { data } = await client.batch.send([
|
|
|
128
128
|
console.log(data?.data) // [{ id: '...' }, { id: '...' }]
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
+
Pass an `idempotencyKey` as the second argument to retry a batch safely. The key is applied per item by position, so a retry must send the items in the same order.
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
await client.batch.send(emails, { idempotencyKey: `digest-${runId}` })
|
|
135
|
+
```
|
|
136
|
+
|
|
131
137
|
### Retrieve an email
|
|
132
138
|
|
|
133
139
|
```ts
|
|
@@ -204,9 +210,12 @@ const { data } = await client.domains.get(domainId)
|
|
|
204
210
|
### Delete a domain
|
|
205
211
|
|
|
206
212
|
```ts
|
|
207
|
-
await client.domains.delete(domainId)
|
|
213
|
+
const { data } = await client.domains.delete(domainId)
|
|
214
|
+
// { message, canceled_scheduled_emails }
|
|
208
215
|
```
|
|
209
216
|
|
|
217
|
+
Scheduled emails from the domain are canceled, since it can no longer send them.
|
|
218
|
+
|
|
210
219
|
---
|
|
211
220
|
|
|
212
221
|
## API Keys
|
|
@@ -279,6 +288,19 @@ const { data } = await client.audiences.list()
|
|
|
279
288
|
// [{ id, name, createdAt, contactCount }]
|
|
280
289
|
```
|
|
281
290
|
|
|
291
|
+
### Retrieve an audience
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
const { data } = await client.audiences.get(audienceId)
|
|
295
|
+
// { id, name, createdAt, updatedAt, contactCount }
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Rename an audience
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
await client.audiences.update(audienceId, { name: 'Product updates' })
|
|
302
|
+
```
|
|
303
|
+
|
|
282
304
|
### Delete an audience
|
|
283
305
|
|
|
284
306
|
```ts
|
|
@@ -548,7 +570,7 @@ console.log(data?.secret) // signing secret — only returned once, store it sec
|
|
|
548
570
|
|
|
549
571
|
Pass `'*'` in the events array to subscribe to all events.
|
|
550
572
|
|
|
551
|
-
Available events: `email.sent` `email.delivered` `email.bounced` `email.complained` `email.opened` `email.clicked`
|
|
573
|
+
Available events: `email.sent` `email.delivered` `email.bounced` `email.complained` `email.opened` `email.clicked` `email.failed` `email.suppressed`
|
|
552
574
|
|
|
553
575
|
**Endpoint requirements:** the `url` must be a public `http(s)` endpoint — private, loopback, and internal addresses are rejected, both at creation and (after DNS resolution) before each delivery. Your endpoint must respond directly with a `2xx`; redirects (`3xx`) are not followed and are treated as a failed delivery.
|
|
554
576
|
|
|
@@ -595,6 +617,7 @@ const { data } = await client.broadcasts.create({
|
|
|
595
617
|
name: 'May newsletter',
|
|
596
618
|
audienceId: '550e8400-e29b-41d4-a716-446655440000',
|
|
597
619
|
from: 'Sivert <hello@yourdomain.com>',
|
|
620
|
+
replyTo: 'support@yourdomain.com',
|
|
598
621
|
subject: 'May update',
|
|
599
622
|
html: '<p>Hi {{first_name}}, your monthly update is here...</p>',
|
|
600
623
|
})
|
package/dist/index.cjs
CHANGED
|
@@ -91,7 +91,10 @@ var Emails = class {
|
|
|
91
91
|
get(id) {
|
|
92
92
|
return this.client.get(`/emails/${id}`);
|
|
93
93
|
}
|
|
94
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* Reschedule a scheduled email. Fails once the email has started sending, and returns
|
|
96
|
+
* 429 `DAILY_LIMIT_EXCEEDED` when the new day's sending quota is already used up.
|
|
97
|
+
*/
|
|
95
98
|
async update(id, options) {
|
|
96
99
|
const res = await this.client.patch(`/emails/${id}`, { scheduled_at: toIsoString(options.scheduledAt) });
|
|
97
100
|
if (res.error) return res;
|
|
@@ -123,14 +126,19 @@ var Emails = class {
|
|
|
123
126
|
* `emails[i]` was queued, or `{ error, code }` when it was not (unverified
|
|
124
127
|
* domain, suppressed recipients, exhausted quota, …) — failed items never fail
|
|
125
128
|
* the whole batch, so branch on the presence of `id` per item.
|
|
129
|
+
*
|
|
130
|
+
* Pass `{ idempotencyKey }` to retry safely: the key is applied per item by position, so
|
|
131
|
+
* a retry must keep the items in the same order or it will match the wrong emails.
|
|
126
132
|
*/
|
|
127
133
|
var Batch = class {
|
|
128
134
|
constructor(client) {
|
|
129
135
|
this.client = client;
|
|
130
136
|
}
|
|
131
|
-
async send(emails) {
|
|
137
|
+
async send(emails, requestOptions) {
|
|
138
|
+
const extraHeaders = {};
|
|
139
|
+
if (requestOptions?.idempotencyKey) extraHeaders["Idempotency-Key"] = requestOptions.idempotencyKey;
|
|
132
140
|
const payloads = await Promise.all(emails.map(toApiPayload));
|
|
133
|
-
return this.client.post("/emails/batch", payloads);
|
|
141
|
+
return this.client.post("/emails/batch", payloads, extraHeaders);
|
|
134
142
|
}
|
|
135
143
|
};
|
|
136
144
|
//#endregion
|
|
@@ -210,6 +218,13 @@ var Audiences = class {
|
|
|
210
218
|
headers: res.headers
|
|
211
219
|
};
|
|
212
220
|
}
|
|
221
|
+
get(id) {
|
|
222
|
+
return this.client.get(`/audiences/${id}`);
|
|
223
|
+
}
|
|
224
|
+
/** Rename an audience. */
|
|
225
|
+
update(id, options) {
|
|
226
|
+
return this.client.patch(`/audiences/${id}`, { name: options.name });
|
|
227
|
+
}
|
|
213
228
|
delete(id) {
|
|
214
229
|
return this.client.delete(`/audiences/${id}`);
|
|
215
230
|
}
|
|
@@ -358,8 +373,9 @@ var Topics = class {
|
|
|
358
373
|
visibility: options.visibility
|
|
359
374
|
});
|
|
360
375
|
}
|
|
361
|
-
/** Deletes the topic and every stored preference for it. A draft
|
|
362
|
-
*
|
|
376
|
+
/** Deletes the topic and every stored preference for it. A draft broadcast scoped to it
|
|
377
|
+
* widens back to its whole audience; returns 409 while a broadcast that is scheduled or
|
|
378
|
+
* has not finished sending still uses the topic. */
|
|
363
379
|
delete(id) {
|
|
364
380
|
return this.client.delete(`/topics/${id}`);
|
|
365
381
|
}
|
|
@@ -479,6 +495,7 @@ var Broadcasts = class {
|
|
|
479
495
|
audience_id: options.audienceId,
|
|
480
496
|
topic_id: options.topicId,
|
|
481
497
|
from: options.from,
|
|
498
|
+
reply_to: options.replyTo,
|
|
482
499
|
subject: options.subject,
|
|
483
500
|
html,
|
|
484
501
|
template_id: options.templateId,
|
|
@@ -499,6 +516,11 @@ var Broadcasts = class {
|
|
|
499
516
|
get(id) {
|
|
500
517
|
return this.client.get(`/broadcasts/${id}`);
|
|
501
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* An update that leaves the broadcast scheduled — setting `scheduledAt`, or editing one
|
|
521
|
+
* that already is — runs the same checks as `send()` and can return the same 403s.
|
|
522
|
+
* Unscheduling with `scheduledAt: null` is always allowed.
|
|
523
|
+
*/
|
|
502
524
|
async update(id, options) {
|
|
503
525
|
const html = await resolveBroadcastHtml(options);
|
|
504
526
|
return this.client.patch(`/broadcasts/${id}`, {
|
|
@@ -506,6 +528,7 @@ var Broadcasts = class {
|
|
|
506
528
|
audience_id: options.audienceId,
|
|
507
529
|
topic_id: options.topicId,
|
|
508
530
|
from: options.from,
|
|
531
|
+
reply_to: options.replyTo,
|
|
509
532
|
subject: options.subject,
|
|
510
533
|
html,
|
|
511
534
|
template_id: options.templateId,
|
|
@@ -616,7 +639,7 @@ var Suppressions = class {
|
|
|
616
639
|
//#endregion
|
|
617
640
|
//#region src/eusend.ts
|
|
618
641
|
const DEFAULT_BASE_URL = "https://api.eusend.dev";
|
|
619
|
-
const SDK_VERSION = "0.
|
|
642
|
+
const SDK_VERSION = "0.19.0";
|
|
620
643
|
var Eusend = class {
|
|
621
644
|
constructor(key, options) {
|
|
622
645
|
const apiKey = key ?? (typeof process !== "undefined" ? process.env["EUSEND_API_KEY"] : void 0);
|
package/dist/index.d.cts
CHANGED
|
@@ -204,7 +204,10 @@ declare class Emails {
|
|
|
204
204
|
send(options: SendEmailOptions, requestOptions?: SendEmailRequestOptions): Promise<EusendResponse<SendEmailResponse>>;
|
|
205
205
|
list(options?: ListEmailsOptions): Promise<EusendResponse<ListEmailsResponse>>;
|
|
206
206
|
get(id: string): Promise<EusendResponse<Email>>;
|
|
207
|
-
/**
|
|
207
|
+
/**
|
|
208
|
+
* Reschedule a scheduled email. Fails once the email has started sending, and returns
|
|
209
|
+
* 429 `DAILY_LIMIT_EXCEEDED` when the new day's sending quota is already used up.
|
|
210
|
+
*/
|
|
208
211
|
update(id: string, options: UpdateEmailOptions): Promise<EusendResponse<UpdateEmailResponse>>;
|
|
209
212
|
/** Cancel a scheduled email. Fails once the email has started sending. */
|
|
210
213
|
cancel(id: string): Promise<EusendResponse<CancelEmailResponse>>;
|
|
@@ -222,11 +225,14 @@ declare class Emails {
|
|
|
222
225
|
* `emails[i]` was queued, or `{ error, code }` when it was not (unverified
|
|
223
226
|
* domain, suppressed recipients, exhausted quota, …) — failed items never fail
|
|
224
227
|
* the whole batch, so branch on the presence of `id` per item.
|
|
228
|
+
*
|
|
229
|
+
* Pass `{ idempotencyKey }` to retry safely: the key is applied per item by position, so
|
|
230
|
+
* a retry must keep the items in the same order or it will match the wrong emails.
|
|
225
231
|
*/
|
|
226
232
|
declare class Batch {
|
|
227
233
|
private readonly client;
|
|
228
234
|
constructor(client: Eusend);
|
|
229
|
-
send(emails: SendEmailOptions[]): Promise<EusendResponse<BatchSendResponse>>;
|
|
235
|
+
send(emails: SendEmailOptions[], requestOptions?: SendEmailRequestOptions): Promise<EusendResponse<BatchSendResponse>>;
|
|
230
236
|
}
|
|
231
237
|
//#endregion
|
|
232
238
|
//#region src/domains.d.ts
|
|
@@ -306,15 +312,18 @@ interface Domain {
|
|
|
306
312
|
/** Null while nothing is wrong beyond the records not having propagated yet. */
|
|
307
313
|
diagnostic: DomainDiagnostic | null;
|
|
308
314
|
}
|
|
315
|
+
interface DeleteDomainResponse {
|
|
316
|
+
message: string;
|
|
317
|
+
/** Scheduled emails from this domain that were canceled because it can no longer send. */
|
|
318
|
+
canceled_scheduled_emails: number;
|
|
319
|
+
}
|
|
309
320
|
declare class Domains {
|
|
310
321
|
private readonly client;
|
|
311
322
|
constructor(client: Eusend);
|
|
312
323
|
create(name: string): Promise<EusendResponse<CreateDomainResponse>>;
|
|
313
324
|
list(): Promise<EusendResponse<DomainListItem[]>>;
|
|
314
325
|
get(id: string): Promise<EusendResponse<Domain>>;
|
|
315
|
-
delete(id: string): Promise<EusendResponse<
|
|
316
|
-
message: string;
|
|
317
|
-
}>>;
|
|
326
|
+
delete(id: string): Promise<EusendResponse<DeleteDomainResponse>>;
|
|
318
327
|
verify(id: string): Promise<EusendResponse<{
|
|
319
328
|
message: string;
|
|
320
329
|
}>>;
|
|
@@ -384,6 +393,12 @@ interface AudienceListItem {
|
|
|
384
393
|
createdAt: string;
|
|
385
394
|
contactCount: number;
|
|
386
395
|
}
|
|
396
|
+
interface AudienceDetail extends AudienceListItem {
|
|
397
|
+
updatedAt: string;
|
|
398
|
+
}
|
|
399
|
+
interface UpdateAudienceOptions {
|
|
400
|
+
name: string;
|
|
401
|
+
}
|
|
387
402
|
interface Contact {
|
|
388
403
|
id: string;
|
|
389
404
|
audienceId: string;
|
|
@@ -462,6 +477,9 @@ declare class Audiences {
|
|
|
462
477
|
constructor(client: Eusend);
|
|
463
478
|
create(name: string): Promise<EusendResponse<Audience>>;
|
|
464
479
|
list(): Promise<EusendResponse<AudienceListItem[]>>;
|
|
480
|
+
get(id: string): Promise<EusendResponse<AudienceDetail>>;
|
|
481
|
+
/** Rename an audience. */
|
|
482
|
+
update(id: string, options: UpdateAudienceOptions): Promise<EusendResponse<Audience>>;
|
|
465
483
|
delete(id: string): Promise<EusendResponse<Record<string, never>>>;
|
|
466
484
|
createContact(audienceId: string, options: CreateContactOptions): Promise<EusendResponse<Contact>>;
|
|
467
485
|
listContacts(audienceId: string, options?: ListContactsOptions): Promise<EusendResponse<ListContactsResponse>>;
|
|
@@ -610,8 +628,9 @@ declare class Topics {
|
|
|
610
628
|
list(): Promise<EusendResponse<Topic[]>>;
|
|
611
629
|
get(id: string): Promise<EusendResponse<Topic>>;
|
|
612
630
|
update(id: string, options: UpdateTopicOptions): Promise<EusendResponse<Topic>>;
|
|
613
|
-
/** Deletes the topic and every stored preference for it. A draft
|
|
614
|
-
*
|
|
631
|
+
/** Deletes the topic and every stored preference for it. A draft broadcast scoped to it
|
|
632
|
+
* widens back to its whole audience; returns 409 while a broadcast that is scheduled or
|
|
633
|
+
* has not finished sending still uses the topic. */
|
|
615
634
|
delete(id: string): Promise<EusendResponse<DeleteTopicResponse>>;
|
|
616
635
|
/** Record an explicit preference for one contact. */
|
|
617
636
|
subscribe(topicId: string, contactId: string, subscribed?: boolean): Promise<EusendResponse<TopicSubscriptionResponse>>;
|
|
@@ -670,7 +689,7 @@ declare class Templates {
|
|
|
670
689
|
}
|
|
671
690
|
//#endregion
|
|
672
691
|
//#region src/webhooks.d.ts
|
|
673
|
-
type WebhookEvent = 'email.sent' | 'email.delivered' | 'email.bounced' | 'email.complained' | 'email.opened' | 'email.clicked' | '*';
|
|
692
|
+
type WebhookEvent = 'email.sent' | 'email.delivered' | 'email.bounced' | 'email.complained' | 'email.opened' | 'email.clicked' | 'email.failed' | 'email.suppressed' | '*';
|
|
674
693
|
interface CreateWebhookOptions {
|
|
675
694
|
url: string;
|
|
676
695
|
events: WebhookEvent[];
|
|
@@ -730,6 +749,8 @@ interface CreateBroadcastOptions {
|
|
|
730
749
|
* form (`Acme <onboarding@eusend.dev>`). The domain must be verified on your account.
|
|
731
750
|
*/
|
|
732
751
|
from: string;
|
|
752
|
+
/** Where replies go. Same formats as `from`; omit to have replies go to the sender. */
|
|
753
|
+
replyTo?: string;
|
|
733
754
|
subject: string;
|
|
734
755
|
html?: string;
|
|
735
756
|
/**
|
|
@@ -757,6 +778,8 @@ interface UpdateBroadcastOptions {
|
|
|
757
778
|
/** Pass null to clear the topic and widen the send back to the whole audience. */
|
|
758
779
|
topicId?: string | null;
|
|
759
780
|
from?: string;
|
|
781
|
+
/** Pass null to clear it, so replies go back to the sender. */
|
|
782
|
+
replyTo?: string | null;
|
|
760
783
|
subject?: string;
|
|
761
784
|
html?: string;
|
|
762
785
|
/**
|
|
@@ -856,6 +879,11 @@ declare class Broadcasts {
|
|
|
856
879
|
create(options: CreateBroadcastOptions): Promise<EusendResponse<Broadcast>>;
|
|
857
880
|
list(): Promise<EusendResponse<BroadcastListItem[]>>;
|
|
858
881
|
get(id: string): Promise<EusendResponse<BroadcastDetail>>;
|
|
882
|
+
/**
|
|
883
|
+
* An update that leaves the broadcast scheduled — setting `scheduledAt`, or editing one
|
|
884
|
+
* that already is — runs the same checks as `send()` and can return the same 403s.
|
|
885
|
+
* Unscheduling with `scheduledAt: null` is always allowed.
|
|
886
|
+
*/
|
|
859
887
|
update(id: string, options: UpdateBroadcastOptions): Promise<EusendResponse<Broadcast>>;
|
|
860
888
|
send(id: string, options?: SendBroadcastOptions): Promise<EusendResponse<SendBroadcastResponse>>;
|
|
861
889
|
/**
|
|
@@ -976,5 +1004,5 @@ declare class Eusend {
|
|
|
976
1004
|
delete<T>(path: string): Promise<EusendResponse<T>>;
|
|
977
1005
|
}
|
|
978
1006
|
//#endregion
|
|
979
|
-
export { type ApiKey, type ApiKeyPermission, type Attachment, type Audience, type AudienceListItem, type BatchContactOptions, type BatchCreateContactsOptions, type BatchItemResult, type BatchSendResponse, type Broadcast, type BroadcastDetail, type BroadcastListItem, type BroadcastStatus, type CancelEmailResponse, type ClearTopicSubscriptionResponse, type Contact, type ContactProperty, type ContactPropertyType, type ContactStatus, type CreateApiKeyOptions, type CreateApiKeyResponse, type CreateBroadcastOptions, type CreateContactOptions, type CreateContactPropertyOptions, type CreateDomainResponse, type CreateSuppressionOptions, type CreateTemplateOptions, type CreateTopicOptions, type CreateWebhookOptions, type CreateWebhookResponse, type DeleteContactPropertyResponse, type DeleteTopicResponse, type DnsRecord, type Domain, type DomainDiagnostic, type DomainListItem, type DomainStatus, type DomainVerification, type Email, type EmailEvent, type EmailEventType, type EmailListItem, type EmailStatus, Eusend, type EusendError, type EusendErrorCode, type EusendOptions, type EusendResponse, type ImportSuppressionsResponse, type ListContactsOptions, type ListContactsResponse, type ListEmailsOptions, type ListEmailsResponse, type ListSuppressionsOptions, type ListSuppressionsResponse, type SendBroadcastOptions, type SendBroadcastResponse, type SendEmailOptions, type SendEmailRequestOptions, type SendEmailResponse, type SuppressionEntry, type SuppressionImportItem, type SuppressionReason, type Template, type TemplateListItem, type TestBroadcastOptions, type TestBroadcastResponse, type Topic, type TopicDefaultSubscription, type TopicSubscriptionResponse, type TopicVisibility, type UpdateBroadcastOptions, type UpdateContactOptions, type UpdateContactPropertyOptions, type UpdateEmailOptions, type UpdateEmailResponse, type UpdateTemplateOptions, type UpdateTopicOptions, type UpdateWebhookOptions, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookWithDeliveries };
|
|
1007
|
+
export { type ApiKey, type ApiKeyPermission, type Attachment, type Audience, type AudienceDetail, type AudienceListItem, type BatchContactOptions, type BatchCreateContactsOptions, type BatchItemResult, type BatchSendResponse, type Broadcast, type BroadcastDetail, type BroadcastListItem, type BroadcastStatus, type CancelEmailResponse, type ClearTopicSubscriptionResponse, type Contact, type ContactProperty, type ContactPropertyType, type ContactStatus, type CreateApiKeyOptions, type CreateApiKeyResponse, type CreateBroadcastOptions, type CreateContactOptions, type CreateContactPropertyOptions, type CreateDomainResponse, type CreateSuppressionOptions, type CreateTemplateOptions, type CreateTopicOptions, type CreateWebhookOptions, type CreateWebhookResponse, type DeleteContactPropertyResponse, type DeleteDomainResponse, type DeleteTopicResponse, type DnsRecord, type Domain, type DomainDiagnostic, type DomainListItem, type DomainStatus, type DomainVerification, type Email, type EmailEvent, type EmailEventType, type EmailListItem, type EmailStatus, Eusend, type EusendError, type EusendErrorCode, type EusendOptions, type EusendResponse, type ImportSuppressionsResponse, type ListContactsOptions, type ListContactsResponse, type ListEmailsOptions, type ListEmailsResponse, type ListSuppressionsOptions, type ListSuppressionsResponse, type SendBroadcastOptions, type SendBroadcastResponse, type SendEmailOptions, type SendEmailRequestOptions, type SendEmailResponse, type SuppressionEntry, type SuppressionImportItem, type SuppressionReason, type Template, type TemplateListItem, type TestBroadcastOptions, type TestBroadcastResponse, type Topic, type TopicDefaultSubscription, type TopicSubscriptionResponse, type TopicVisibility, type UpdateAudienceOptions, type UpdateBroadcastOptions, type UpdateContactOptions, type UpdateContactPropertyOptions, type UpdateEmailOptions, type UpdateEmailResponse, type UpdateTemplateOptions, type UpdateTopicOptions, type UpdateWebhookOptions, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookWithDeliveries };
|
|
980
1008
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/interfaces.ts","../src/react-render.ts","../src/emails.ts","../src/batch.ts","../src/domains.ts","../src/api-keys.ts","../src/audiences.ts","../src/contact-properties.ts","../src/topics.ts","../src/templates.ts","../src/webhooks.ts","../src/broadcasts.ts","../src/suppressions.ts","../src/eusend.ts"],"mappings":";KAAY;UA2BK;EACf;EACA;EACA,MAAM;;KAGI,eAAe;EACrB,MAAM;EAAG;EAAa,SAAS;;EAC/B;EAAY,OAAO;EAAa,SAAS;;;;KChCnC;WACD;WACA;WACA;;;;KCFC;KAYA;UAEK;;EAEf;;;;;;EAMA,mBAAmB;;;;;;EAMnB;;EAEA;;;;;EAKA;;;UAIe;EACf;EACA;;;;;;;;;;;;KAaU,YAAY,yBAAyB;UAEhC;;;;;EAKf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;EAMA,QAAQ;EACR;EACA,YAAY;EACZ,UAAU;;;;;;EAMV,OAAO;EACP;EACA;;EAEA,cAAc;;;;;;;;;EASd,uBAAuB;;UAGR;EACf;;UAGe;EACf;;;;;;;;;KAUU;EACR;EAAY;EAAe;;EAAmB;EAAY;EAAe,MAAM;;UAElE;EACf,MAAM;;UAGS;EACf;EACA,MAAM;EACN,UAAU;EACV;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;;EAER,MAAM;EACN;EACA;;EAEA;EACA;EACA,QAAQ;;UAGO;;;EAGf,sBAAsB;;UAGP;EACf;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA,QAAQ;;EAER,MAAM;EACN;EACA;;UAGe;EACf;EACA;EACA,SAAS;EACT;EACA;;;;;EAKA;;UAGe;EACf,MAAM;EACN;;cAkDW;mBACkB;EAAA,YAAA,QAAQ;EAE/B,KACJ,SAAS,kBACT,iBAAiB,0BAChB,QAAQ,eAAe;EASpB,KAAK,UAAS,oBAAyB,QAAQ,eAAe;EAwBpE,IAAI,aAAa,QAAQ,eAAe
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/interfaces.ts","../src/react-render.ts","../src/emails.ts","../src/batch.ts","../src/domains.ts","../src/api-keys.ts","../src/audiences.ts","../src/contact-properties.ts","../src/topics.ts","../src/templates.ts","../src/webhooks.ts","../src/broadcasts.ts","../src/suppressions.ts","../src/eusend.ts"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -204,7 +204,10 @@ declare class Emails {
|
|
|
204
204
|
send(options: SendEmailOptions, requestOptions?: SendEmailRequestOptions): Promise<EusendResponse<SendEmailResponse>>;
|
|
205
205
|
list(options?: ListEmailsOptions): Promise<EusendResponse<ListEmailsResponse>>;
|
|
206
206
|
get(id: string): Promise<EusendResponse<Email>>;
|
|
207
|
-
/**
|
|
207
|
+
/**
|
|
208
|
+
* Reschedule a scheduled email. Fails once the email has started sending, and returns
|
|
209
|
+
* 429 `DAILY_LIMIT_EXCEEDED` when the new day's sending quota is already used up.
|
|
210
|
+
*/
|
|
208
211
|
update(id: string, options: UpdateEmailOptions): Promise<EusendResponse<UpdateEmailResponse>>;
|
|
209
212
|
/** Cancel a scheduled email. Fails once the email has started sending. */
|
|
210
213
|
cancel(id: string): Promise<EusendResponse<CancelEmailResponse>>;
|
|
@@ -222,11 +225,14 @@ declare class Emails {
|
|
|
222
225
|
* `emails[i]` was queued, or `{ error, code }` when it was not (unverified
|
|
223
226
|
* domain, suppressed recipients, exhausted quota, …) — failed items never fail
|
|
224
227
|
* the whole batch, so branch on the presence of `id` per item.
|
|
228
|
+
*
|
|
229
|
+
* Pass `{ idempotencyKey }` to retry safely: the key is applied per item by position, so
|
|
230
|
+
* a retry must keep the items in the same order or it will match the wrong emails.
|
|
225
231
|
*/
|
|
226
232
|
declare class Batch {
|
|
227
233
|
private readonly client;
|
|
228
234
|
constructor(client: Eusend);
|
|
229
|
-
send(emails: SendEmailOptions[]): Promise<EusendResponse<BatchSendResponse>>;
|
|
235
|
+
send(emails: SendEmailOptions[], requestOptions?: SendEmailRequestOptions): Promise<EusendResponse<BatchSendResponse>>;
|
|
230
236
|
}
|
|
231
237
|
//#endregion
|
|
232
238
|
//#region src/domains.d.ts
|
|
@@ -306,15 +312,18 @@ interface Domain {
|
|
|
306
312
|
/** Null while nothing is wrong beyond the records not having propagated yet. */
|
|
307
313
|
diagnostic: DomainDiagnostic | null;
|
|
308
314
|
}
|
|
315
|
+
interface DeleteDomainResponse {
|
|
316
|
+
message: string;
|
|
317
|
+
/** Scheduled emails from this domain that were canceled because it can no longer send. */
|
|
318
|
+
canceled_scheduled_emails: number;
|
|
319
|
+
}
|
|
309
320
|
declare class Domains {
|
|
310
321
|
private readonly client;
|
|
311
322
|
constructor(client: Eusend);
|
|
312
323
|
create(name: string): Promise<EusendResponse<CreateDomainResponse>>;
|
|
313
324
|
list(): Promise<EusendResponse<DomainListItem[]>>;
|
|
314
325
|
get(id: string): Promise<EusendResponse<Domain>>;
|
|
315
|
-
delete(id: string): Promise<EusendResponse<
|
|
316
|
-
message: string;
|
|
317
|
-
}>>;
|
|
326
|
+
delete(id: string): Promise<EusendResponse<DeleteDomainResponse>>;
|
|
318
327
|
verify(id: string): Promise<EusendResponse<{
|
|
319
328
|
message: string;
|
|
320
329
|
}>>;
|
|
@@ -384,6 +393,12 @@ interface AudienceListItem {
|
|
|
384
393
|
createdAt: string;
|
|
385
394
|
contactCount: number;
|
|
386
395
|
}
|
|
396
|
+
interface AudienceDetail extends AudienceListItem {
|
|
397
|
+
updatedAt: string;
|
|
398
|
+
}
|
|
399
|
+
interface UpdateAudienceOptions {
|
|
400
|
+
name: string;
|
|
401
|
+
}
|
|
387
402
|
interface Contact {
|
|
388
403
|
id: string;
|
|
389
404
|
audienceId: string;
|
|
@@ -462,6 +477,9 @@ declare class Audiences {
|
|
|
462
477
|
constructor(client: Eusend);
|
|
463
478
|
create(name: string): Promise<EusendResponse<Audience>>;
|
|
464
479
|
list(): Promise<EusendResponse<AudienceListItem[]>>;
|
|
480
|
+
get(id: string): Promise<EusendResponse<AudienceDetail>>;
|
|
481
|
+
/** Rename an audience. */
|
|
482
|
+
update(id: string, options: UpdateAudienceOptions): Promise<EusendResponse<Audience>>;
|
|
465
483
|
delete(id: string): Promise<EusendResponse<Record<string, never>>>;
|
|
466
484
|
createContact(audienceId: string, options: CreateContactOptions): Promise<EusendResponse<Contact>>;
|
|
467
485
|
listContacts(audienceId: string, options?: ListContactsOptions): Promise<EusendResponse<ListContactsResponse>>;
|
|
@@ -610,8 +628,9 @@ declare class Topics {
|
|
|
610
628
|
list(): Promise<EusendResponse<Topic[]>>;
|
|
611
629
|
get(id: string): Promise<EusendResponse<Topic>>;
|
|
612
630
|
update(id: string, options: UpdateTopicOptions): Promise<EusendResponse<Topic>>;
|
|
613
|
-
/** Deletes the topic and every stored preference for it. A draft
|
|
614
|
-
*
|
|
631
|
+
/** Deletes the topic and every stored preference for it. A draft broadcast scoped to it
|
|
632
|
+
* widens back to its whole audience; returns 409 while a broadcast that is scheduled or
|
|
633
|
+
* has not finished sending still uses the topic. */
|
|
615
634
|
delete(id: string): Promise<EusendResponse<DeleteTopicResponse>>;
|
|
616
635
|
/** Record an explicit preference for one contact. */
|
|
617
636
|
subscribe(topicId: string, contactId: string, subscribed?: boolean): Promise<EusendResponse<TopicSubscriptionResponse>>;
|
|
@@ -670,7 +689,7 @@ declare class Templates {
|
|
|
670
689
|
}
|
|
671
690
|
//#endregion
|
|
672
691
|
//#region src/webhooks.d.ts
|
|
673
|
-
type WebhookEvent = 'email.sent' | 'email.delivered' | 'email.bounced' | 'email.complained' | 'email.opened' | 'email.clicked' | '*';
|
|
692
|
+
type WebhookEvent = 'email.sent' | 'email.delivered' | 'email.bounced' | 'email.complained' | 'email.opened' | 'email.clicked' | 'email.failed' | 'email.suppressed' | '*';
|
|
674
693
|
interface CreateWebhookOptions {
|
|
675
694
|
url: string;
|
|
676
695
|
events: WebhookEvent[];
|
|
@@ -730,6 +749,8 @@ interface CreateBroadcastOptions {
|
|
|
730
749
|
* form (`Acme <onboarding@eusend.dev>`). The domain must be verified on your account.
|
|
731
750
|
*/
|
|
732
751
|
from: string;
|
|
752
|
+
/** Where replies go. Same formats as `from`; omit to have replies go to the sender. */
|
|
753
|
+
replyTo?: string;
|
|
733
754
|
subject: string;
|
|
734
755
|
html?: string;
|
|
735
756
|
/**
|
|
@@ -757,6 +778,8 @@ interface UpdateBroadcastOptions {
|
|
|
757
778
|
/** Pass null to clear the topic and widen the send back to the whole audience. */
|
|
758
779
|
topicId?: string | null;
|
|
759
780
|
from?: string;
|
|
781
|
+
/** Pass null to clear it, so replies go back to the sender. */
|
|
782
|
+
replyTo?: string | null;
|
|
760
783
|
subject?: string;
|
|
761
784
|
html?: string;
|
|
762
785
|
/**
|
|
@@ -856,6 +879,11 @@ declare class Broadcasts {
|
|
|
856
879
|
create(options: CreateBroadcastOptions): Promise<EusendResponse<Broadcast>>;
|
|
857
880
|
list(): Promise<EusendResponse<BroadcastListItem[]>>;
|
|
858
881
|
get(id: string): Promise<EusendResponse<BroadcastDetail>>;
|
|
882
|
+
/**
|
|
883
|
+
* An update that leaves the broadcast scheduled — setting `scheduledAt`, or editing one
|
|
884
|
+
* that already is — runs the same checks as `send()` and can return the same 403s.
|
|
885
|
+
* Unscheduling with `scheduledAt: null` is always allowed.
|
|
886
|
+
*/
|
|
859
887
|
update(id: string, options: UpdateBroadcastOptions): Promise<EusendResponse<Broadcast>>;
|
|
860
888
|
send(id: string, options?: SendBroadcastOptions): Promise<EusendResponse<SendBroadcastResponse>>;
|
|
861
889
|
/**
|
|
@@ -976,5 +1004,5 @@ declare class Eusend {
|
|
|
976
1004
|
delete<T>(path: string): Promise<EusendResponse<T>>;
|
|
977
1005
|
}
|
|
978
1006
|
//#endregion
|
|
979
|
-
export { type ApiKey, type ApiKeyPermission, type Attachment, type Audience, type AudienceListItem, type BatchContactOptions, type BatchCreateContactsOptions, type BatchItemResult, type BatchSendResponse, type Broadcast, type BroadcastDetail, type BroadcastListItem, type BroadcastStatus, type CancelEmailResponse, type ClearTopicSubscriptionResponse, type Contact, type ContactProperty, type ContactPropertyType, type ContactStatus, type CreateApiKeyOptions, type CreateApiKeyResponse, type CreateBroadcastOptions, type CreateContactOptions, type CreateContactPropertyOptions, type CreateDomainResponse, type CreateSuppressionOptions, type CreateTemplateOptions, type CreateTopicOptions, type CreateWebhookOptions, type CreateWebhookResponse, type DeleteContactPropertyResponse, type DeleteTopicResponse, type DnsRecord, type Domain, type DomainDiagnostic, type DomainListItem, type DomainStatus, type DomainVerification, type Email, type EmailEvent, type EmailEventType, type EmailListItem, type EmailStatus, Eusend, type EusendError, type EusendErrorCode, type EusendOptions, type EusendResponse, type ImportSuppressionsResponse, type ListContactsOptions, type ListContactsResponse, type ListEmailsOptions, type ListEmailsResponse, type ListSuppressionsOptions, type ListSuppressionsResponse, type SendBroadcastOptions, type SendBroadcastResponse, type SendEmailOptions, type SendEmailRequestOptions, type SendEmailResponse, type SuppressionEntry, type SuppressionImportItem, type SuppressionReason, type Template, type TemplateListItem, type TestBroadcastOptions, type TestBroadcastResponse, type Topic, type TopicDefaultSubscription, type TopicSubscriptionResponse, type TopicVisibility, type UpdateBroadcastOptions, type UpdateContactOptions, type UpdateContactPropertyOptions, type UpdateEmailOptions, type UpdateEmailResponse, type UpdateTemplateOptions, type UpdateTopicOptions, type UpdateWebhookOptions, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookWithDeliveries };
|
|
1007
|
+
export { type ApiKey, type ApiKeyPermission, type Attachment, type Audience, type AudienceDetail, type AudienceListItem, type BatchContactOptions, type BatchCreateContactsOptions, type BatchItemResult, type BatchSendResponse, type Broadcast, type BroadcastDetail, type BroadcastListItem, type BroadcastStatus, type CancelEmailResponse, type ClearTopicSubscriptionResponse, type Contact, type ContactProperty, type ContactPropertyType, type ContactStatus, type CreateApiKeyOptions, type CreateApiKeyResponse, type CreateBroadcastOptions, type CreateContactOptions, type CreateContactPropertyOptions, type CreateDomainResponse, type CreateSuppressionOptions, type CreateTemplateOptions, type CreateTopicOptions, type CreateWebhookOptions, type CreateWebhookResponse, type DeleteContactPropertyResponse, type DeleteDomainResponse, type DeleteTopicResponse, type DnsRecord, type Domain, type DomainDiagnostic, type DomainListItem, type DomainStatus, type DomainVerification, type Email, type EmailEvent, type EmailEventType, type EmailListItem, type EmailStatus, Eusend, type EusendError, type EusendErrorCode, type EusendOptions, type EusendResponse, type ImportSuppressionsResponse, type ListContactsOptions, type ListContactsResponse, type ListEmailsOptions, type ListEmailsResponse, type ListSuppressionsOptions, type ListSuppressionsResponse, type SendBroadcastOptions, type SendBroadcastResponse, type SendEmailOptions, type SendEmailRequestOptions, type SendEmailResponse, type SuppressionEntry, type SuppressionImportItem, type SuppressionReason, type Template, type TemplateListItem, type TestBroadcastOptions, type TestBroadcastResponse, type Topic, type TopicDefaultSubscription, type TopicSubscriptionResponse, type TopicVisibility, type UpdateAudienceOptions, type UpdateBroadcastOptions, type UpdateContactOptions, type UpdateContactPropertyOptions, type UpdateEmailOptions, type UpdateEmailResponse, type UpdateTemplateOptions, type UpdateTopicOptions, type UpdateWebhookOptions, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookWithDeliveries };
|
|
980
1008
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/interfaces.ts","../src/react-render.ts","../src/emails.ts","../src/batch.ts","../src/domains.ts","../src/api-keys.ts","../src/audiences.ts","../src/contact-properties.ts","../src/topics.ts","../src/templates.ts","../src/webhooks.ts","../src/broadcasts.ts","../src/suppressions.ts","../src/eusend.ts"],"mappings":";KAAY;UA2BK;EACf;EACA;EACA,MAAM;;KAGI,eAAe;EACrB,MAAM;EAAG;EAAa,SAAS;;EAC/B;EAAY,OAAO;EAAa,SAAS;;;;KChCnC;WACD;WACA;WACA;;;;KCFC;KAYA;UAEK;;EAEf;;;;;;EAMA,mBAAmB;;;;;;EAMnB;;EAEA;;;;;EAKA;;;UAIe;EACf;EACA;;;;;;;;;;;;KAaU,YAAY,yBAAyB;UAEhC;;;;;EAKf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;EAMA,QAAQ;EACR;EACA,YAAY;EACZ,UAAU;;;;;;EAMV,OAAO;EACP;EACA;;EAEA,cAAc;;;;;;;;;EASd,uBAAuB;;UAGR;EACf;;UAGe;EACf;;;;;;;;;KAUU;EACR;EAAY;EAAe;;EAAmB;EAAY;EAAe,MAAM;;UAElE;EACf,MAAM;;UAGS;EACf;EACA,MAAM;EACN,UAAU;EACV;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;;EAER,MAAM;EACN;EACA;;EAEA;EACA;EACA,QAAQ;;UAGO;;;EAGf,sBAAsB;;UAGP;EACf;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA,QAAQ;;EAER,MAAM;EACN;EACA;;UAGe;EACf;EACA;EACA,SAAS;EACT;EACA;;;;;EAKA;;UAGe;EACf,MAAM;EACN;;cAkDW;mBACkB;EAAA,YAAA,QAAQ;EAE/B,KACJ,SAAS,kBACT,iBAAiB,0BAChB,QAAQ,eAAe;EASpB,KAAK,UAAS,oBAAyB,QAAQ,eAAe;EAwBpE,IAAI,aAAa,QAAQ,eAAe
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/interfaces.ts","../src/react-render.ts","../src/emails.ts","../src/batch.ts","../src/domains.ts","../src/api-keys.ts","../src/audiences.ts","../src/contact-properties.ts","../src/topics.ts","../src/templates.ts","../src/webhooks.ts","../src/broadcasts.ts","../src/suppressions.ts","../src/eusend.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -90,7 +90,10 @@ var Emails = class {
|
|
|
90
90
|
get(id) {
|
|
91
91
|
return this.client.get(`/emails/${id}`);
|
|
92
92
|
}
|
|
93
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* Reschedule a scheduled email. Fails once the email has started sending, and returns
|
|
95
|
+
* 429 `DAILY_LIMIT_EXCEEDED` when the new day's sending quota is already used up.
|
|
96
|
+
*/
|
|
94
97
|
async update(id, options) {
|
|
95
98
|
const res = await this.client.patch(`/emails/${id}`, { scheduled_at: toIsoString(options.scheduledAt) });
|
|
96
99
|
if (res.error) return res;
|
|
@@ -122,14 +125,19 @@ var Emails = class {
|
|
|
122
125
|
* `emails[i]` was queued, or `{ error, code }` when it was not (unverified
|
|
123
126
|
* domain, suppressed recipients, exhausted quota, …) — failed items never fail
|
|
124
127
|
* the whole batch, so branch on the presence of `id` per item.
|
|
128
|
+
*
|
|
129
|
+
* Pass `{ idempotencyKey }` to retry safely: the key is applied per item by position, so
|
|
130
|
+
* a retry must keep the items in the same order or it will match the wrong emails.
|
|
125
131
|
*/
|
|
126
132
|
var Batch = class {
|
|
127
133
|
constructor(client) {
|
|
128
134
|
this.client = client;
|
|
129
135
|
}
|
|
130
|
-
async send(emails) {
|
|
136
|
+
async send(emails, requestOptions) {
|
|
137
|
+
const extraHeaders = {};
|
|
138
|
+
if (requestOptions?.idempotencyKey) extraHeaders["Idempotency-Key"] = requestOptions.idempotencyKey;
|
|
131
139
|
const payloads = await Promise.all(emails.map(toApiPayload));
|
|
132
|
-
return this.client.post("/emails/batch", payloads);
|
|
140
|
+
return this.client.post("/emails/batch", payloads, extraHeaders);
|
|
133
141
|
}
|
|
134
142
|
};
|
|
135
143
|
//#endregion
|
|
@@ -209,6 +217,13 @@ var Audiences = class {
|
|
|
209
217
|
headers: res.headers
|
|
210
218
|
};
|
|
211
219
|
}
|
|
220
|
+
get(id) {
|
|
221
|
+
return this.client.get(`/audiences/${id}`);
|
|
222
|
+
}
|
|
223
|
+
/** Rename an audience. */
|
|
224
|
+
update(id, options) {
|
|
225
|
+
return this.client.patch(`/audiences/${id}`, { name: options.name });
|
|
226
|
+
}
|
|
212
227
|
delete(id) {
|
|
213
228
|
return this.client.delete(`/audiences/${id}`);
|
|
214
229
|
}
|
|
@@ -357,8 +372,9 @@ var Topics = class {
|
|
|
357
372
|
visibility: options.visibility
|
|
358
373
|
});
|
|
359
374
|
}
|
|
360
|
-
/** Deletes the topic and every stored preference for it. A draft
|
|
361
|
-
*
|
|
375
|
+
/** Deletes the topic and every stored preference for it. A draft broadcast scoped to it
|
|
376
|
+
* widens back to its whole audience; returns 409 while a broadcast that is scheduled or
|
|
377
|
+
* has not finished sending still uses the topic. */
|
|
362
378
|
delete(id) {
|
|
363
379
|
return this.client.delete(`/topics/${id}`);
|
|
364
380
|
}
|
|
@@ -478,6 +494,7 @@ var Broadcasts = class {
|
|
|
478
494
|
audience_id: options.audienceId,
|
|
479
495
|
topic_id: options.topicId,
|
|
480
496
|
from: options.from,
|
|
497
|
+
reply_to: options.replyTo,
|
|
481
498
|
subject: options.subject,
|
|
482
499
|
html,
|
|
483
500
|
template_id: options.templateId,
|
|
@@ -498,6 +515,11 @@ var Broadcasts = class {
|
|
|
498
515
|
get(id) {
|
|
499
516
|
return this.client.get(`/broadcasts/${id}`);
|
|
500
517
|
}
|
|
518
|
+
/**
|
|
519
|
+
* An update that leaves the broadcast scheduled — setting `scheduledAt`, or editing one
|
|
520
|
+
* that already is — runs the same checks as `send()` and can return the same 403s.
|
|
521
|
+
* Unscheduling with `scheduledAt: null` is always allowed.
|
|
522
|
+
*/
|
|
501
523
|
async update(id, options) {
|
|
502
524
|
const html = await resolveBroadcastHtml(options);
|
|
503
525
|
return this.client.patch(`/broadcasts/${id}`, {
|
|
@@ -505,6 +527,7 @@ var Broadcasts = class {
|
|
|
505
527
|
audience_id: options.audienceId,
|
|
506
528
|
topic_id: options.topicId,
|
|
507
529
|
from: options.from,
|
|
530
|
+
reply_to: options.replyTo,
|
|
508
531
|
subject: options.subject,
|
|
509
532
|
html,
|
|
510
533
|
template_id: options.templateId,
|
|
@@ -615,7 +638,7 @@ var Suppressions = class {
|
|
|
615
638
|
//#endregion
|
|
616
639
|
//#region src/eusend.ts
|
|
617
640
|
const DEFAULT_BASE_URL = "https://api.eusend.dev";
|
|
618
|
-
const SDK_VERSION = "0.
|
|
641
|
+
const SDK_VERSION = "0.19.0";
|
|
619
642
|
var Eusend = class {
|
|
620
643
|
constructor(key, options) {
|
|
621
644
|
const apiKey = key ?? (typeof process !== "undefined" ? process.env["EUSEND_API_KEY"] : void 0);
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/react-render.ts","../src/emails.ts","../src/batch.ts","../src/domains.ts","../src/api-keys.ts","../src/audiences.ts","../src/contact-properties.ts","../src/topics.ts","../src/templates.ts","../src/webhooks.ts","../src/broadcasts.ts","../src/suppressions.ts","../src/eusend.ts"],"sourcesContent":["// Minimal structural type so the SDK doesn't take a hard dependency on `react`.\n// Real React elements assignable to this; users who pass `react:` are expected to\n// have `react` and `@react-email/render` installed (declared as optional peers).\nexport type ReactEmailElement = {\n readonly type: unknown\n readonly props: unknown\n readonly key: string | number | null\n}\n\nlet renderPromise: Promise<(element: ReactEmailElement) => Promise<string>> | null = null\n\nasync function getRender(): Promise<(element: ReactEmailElement) => Promise<string>> {\n if (!renderPromise) {\n renderPromise = (async () => {\n try {\n const mod = (await import('@react-email/render')) as {\n render: (element: unknown, options?: { plainText?: boolean }) => Promise<string> | string\n }\n return (element: ReactEmailElement) => Promise.resolve(mod.render(element))\n } catch {\n throw new Error(\n 'Passing `react:` requires `@react-email/render` and `react` to be installed. ' +\n 'Run: npm install @react-email/render react',\n )\n }\n })()\n }\n return renderPromise\n}\n\nexport async function renderReactEmail(element: ReactEmailElement): Promise<string> {\n const render = await getRender()\n return render(element)\n}\n","import type { Eusend } from './eusend'\nimport type { EusendErrorCode, EusendResponse } from './interfaces'\nimport { renderReactEmail, type ReactEmailElement } from './react-render'\n\nexport type EmailStatus =\n | 'queued'\n | 'scheduled'\n | 'canceled'\n | 'sending'\n | 'sent'\n | 'delivered'\n | 'bounced'\n | 'complained'\n | 'suppressed'\n | 'failed'\n\nexport type EmailEventType = 'sent' | 'delivered' | 'opened' | 'clicked' | 'bounced' | 'complained'\n\nexport interface Attachment {\n /** Name the recipient sees for the file, e.g. `invoice.pdf`. */\n filename: string\n /**\n * File contents. A base64-encoded string (sent as-is) or raw bytes\n * (`Uint8Array`/`Buffer`), which the SDK base64-encodes for you. Provide either\n * `content` or `path`, not both.\n */\n content?: string | Uint8Array\n /**\n * A URL the server fetches at send time to attach the file. Use instead of\n * `content` when the bytes live on a public URL. Provide either `content` or `path`,\n * not both.\n */\n path?: string\n /** MIME type, e.g. `application/pdf`. Inferred from the filename when omitted. */\n contentType?: string\n /**\n * Content-ID for an inline attachment. Set it to reference the file from your\n * HTML with `<img src=\"cid:<contentId>\">` instead of showing it as a download.\n */\n contentId?: string\n}\n\n/** A single tag in the `[{ name, value }]` form, for Resend-compatible payloads. */\nexport interface EmailTag {\n name: string\n value: string\n}\n\n/**\n * Labels attached to a send, used to filter your email log and to route webhook events.\n *\n * Accepts either a plain object (`{ category: 'password_reset' }`) or the\n * `[{ name, value }]` array form, so a payload written against Resend works unchanged.\n * Responses and webhook payloads always return the object form.\n *\n * Names and values may contain ASCII letters, numbers, underscores and dashes; up to 10\n * tags per email.\n */\nexport type EmailTags = Record<string, string> | EmailTag[]\n\nexport interface SendEmailOptions {\n /**\n * Sender address. Accepts a bare email (`onboarding@eusend.dev`) or a display-name\n * form (`Acme <onboarding@eusend.dev>`). The domain must be verified on your account.\n */\n from: string\n to: string | string[]\n cc?: string | string[]\n bcc?: string | string[]\n replyTo?: string | string[]\n subject?: string\n html?: string\n text?: string\n /**\n * A React Email component. The SDK renders it to HTML locally before sending\n * — the JSX source never travels over the wire. Requires `@react-email/render`\n * and `react` as peer dependencies. Ignored when `html` is also provided.\n */\n react?: ReactEmailElement\n templateId?: string\n variables?: Record<string, unknown>\n headers?: Record<string, string>\n /**\n * Labels for log filtering and webhook routing, e.g.\n * `{ category: 'password_reset', tier: 'pro' }`. Returned on every `email.*` webhook\n * event for this send.\n */\n tags?: EmailTags\n trackOpens?: boolean\n trackClicks?: boolean\n /** File attachments. Up to 20 per message, 10 MB combined. */\n attachments?: Attachment[]\n /**\n * Schedule the send for a future time, at most 30 days out. Accepts a `Date`, an\n * ISO 8601 string, or a natural-language time like `\"in 1 hour\"` or `\"tomorrow at\n * 9am\"` (parsed server-side, same as Resend). Relative phrasings resolve against the\n * server clock in UTC — pass an offset-qualified ISO string when you need an exact\n * instant. The email is created with status `scheduled`; reschedule it with\n * `emails.update()` or call `emails.cancel()` any time before it sends.\n */\n scheduledAt?: string | Date\n}\n\nexport interface SendEmailRequestOptions {\n idempotencyKey?: string\n}\n\nexport interface SendEmailResponse {\n id: string\n}\n\n/**\n * Per-item outcome of a batch send, positionally mapped to the input array:\n * `data[i]` describes `emails[i]`. Items that were queued carry `{ id }`; items\n * that could not be queued carry `{ error, code }` (e.g. an unverified sender\n * domain, all recipients suppressed, or an exhausted send quota). Branch on the\n * presence of `id`.\n */\nexport type BatchItemResult =\n { id: string; error?: never; code?: never } | { id?: never; error: string; code: EusendErrorCode }\n\nexport interface BatchSendResponse {\n data: BatchItemResult[]\n}\n\nexport interface EmailEvent {\n id: string\n type: EmailEventType\n metadata: Record<string, unknown>\n createdAt: string\n}\n\nexport interface Email {\n id: string\n from: string\n to: string[]\n cc: string[]\n bcc: string[]\n replyTo: string[]\n subject: string\n html: string | null\n text: string | null\n status: EmailStatus\n /** Always the object form, `{}` when the send carried no tags. */\n tags: Record<string, string>\n testMode: boolean\n templateId: string | null\n /** Set only for scheduled sends. */\n scheduledAt: string | null\n createdAt: string\n events: EmailEvent[]\n}\n\nexport interface UpdateEmailOptions {\n /** The new send time, at most 30 days out — a `Date`, an ISO 8601 string, or natural\n * language like `\"in 1 hour\"` (parsed server-side, same as `emails.send`). */\n scheduledAt: string | Date\n}\n\nexport interface UpdateEmailResponse {\n id: string\n status: 'scheduled'\n scheduledAt: string\n}\n\nexport interface CancelEmailResponse {\n id: string\n status: 'canceled'\n}\n\nexport interface EmailListItem {\n id: string\n from: string\n to: string[]\n subject: string\n status: EmailStatus\n /** Always the object form, `{}` when the send carried no tags. */\n tags: Record<string, string>\n testMode: boolean\n createdAt: string\n}\n\nexport interface ListEmailsOptions {\n limit?: number\n cursor?: string\n status?: EmailStatus\n from?: string\n to?: string\n /**\n * Filter by tag. `'category:password_reset'` matches that exact pair; a bare\n * `'category'` matches any email carrying the tag. Pass an array to require several.\n */\n tag?: string | string[]\n}\n\nexport interface ListEmailsResponse {\n data: EmailListItem[]\n nextCursor: string | null\n}\n\nasync function resolveHtml(options: SendEmailOptions): Promise<string | undefined> {\n if (options.html) return options.html\n if (options.react) return renderReactEmail(options.react)\n return undefined\n}\n\nfunction encodeAttachmentContent(content: string | Uint8Array): string {\n // A string is assumed to already be base64. Raw bytes are encoded here.\n if (typeof content === 'string') return content\n if (typeof Buffer !== 'undefined') return Buffer.from(content).toString('base64')\n let binary = ''\n for (const byte of content) binary += String.fromCharCode(byte)\n return btoa(binary)\n}\n\nfunction toIsoString(value: string | Date): string {\n return value instanceof Date ? value.toISOString() : value\n}\n\nexport async function toApiPayload(options: SendEmailOptions) {\n const html = await resolveHtml(options)\n return {\n from: options.from,\n to: options.to,\n cc: options.cc,\n bcc: options.bcc,\n reply_to: options.replyTo,\n subject: options.subject,\n html,\n text: options.text,\n template_id: options.templateId,\n variables: options.variables,\n headers: options.headers,\n tags: options.tags,\n track_opens: options.trackOpens,\n track_clicks: options.trackClicks,\n attachments: options.attachments?.map((a) => ({\n filename: a.filename,\n content: a.content === undefined ? undefined : encodeAttachmentContent(a.content),\n path: a.path,\n content_type: a.contentType,\n content_id: a.contentId,\n })),\n scheduled_at: options.scheduledAt ? toIsoString(options.scheduledAt) : undefined,\n }\n}\n\nexport class Emails {\n constructor(private readonly client: Eusend) {}\n\n async send(\n options: SendEmailOptions,\n requestOptions?: SendEmailRequestOptions,\n ): Promise<EusendResponse<SendEmailResponse>> {\n const extraHeaders: Record<string, string> = {}\n if (requestOptions?.idempotencyKey) {\n extraHeaders['Idempotency-Key'] = requestOptions.idempotencyKey\n }\n const payload = await toApiPayload(options)\n return this.client.post<SendEmailResponse>('/emails', payload, extraHeaders)\n }\n\n async list(options: ListEmailsOptions = {}): Promise<EusendResponse<ListEmailsResponse>> {\n const params = new URLSearchParams()\n if (options.limit != null) params.set('limit', String(options.limit))\n if (options.cursor) params.set('cursor', options.cursor)\n if (options.status) params.set('status', options.status)\n if (options.from) params.set('from', options.from)\n if (options.to) params.set('to', options.to)\n // Repeated `tag` params, one per filter — the API ANDs them.\n for (const tag of options.tag == null ? [] : [options.tag].flat()) {\n params.append('tag', tag)\n }\n const qs = params.toString()\n\n const res = await this.client.get<{ data: EmailListItem[]; next_cursor: string | null }>(\n qs ? `/emails?${qs}` : '/emails',\n )\n if (res.error) return res\n return {\n data: { data: res.data.data, nextCursor: res.data.next_cursor },\n error: null,\n headers: res.headers,\n }\n }\n\n get(id: string): Promise<EusendResponse<Email>> {\n return this.client.get<Email>(`/emails/${id}`)\n }\n\n /** Reschedule a scheduled email. Fails once the email has started sending. */\n async update(\n id: string,\n options: UpdateEmailOptions,\n ): Promise<EusendResponse<UpdateEmailResponse>> {\n const res = await this.client.patch<{ id: string; status: 'scheduled'; scheduled_at: string }>(\n `/emails/${id}`,\n { scheduled_at: toIsoString(options.scheduledAt) },\n )\n if (res.error) return res\n return {\n data: { id: res.data.id, status: res.data.status, scheduledAt: res.data.scheduled_at },\n error: null,\n headers: res.headers,\n }\n }\n\n /** Cancel a scheduled email. Fails once the email has started sending. */\n cancel(id: string): Promise<EusendResponse<CancelEmailResponse>> {\n return this.client.post<CancelEmailResponse>(`/emails/${id}/cancel`, undefined)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\nimport { toApiPayload, type SendEmailOptions, type BatchSendResponse } from './emails'\n\n/**\n * Batch sending — `eusend.batch.send([...])`. The method path mirrors Resend's\n * `resend.batch.send([...])`, so migrating is a mechanical `resend` → `eusend` rename.\n * The HTTP body is a top-level array of email objects (POST /emails/batch), up to 100\n * per request. As with Resend, attachments and `scheduledAt` are not supported on the\n * batch endpoint — send those individually via `emails.send`.\n *\n * The response maps positionally to the input: `data[i]` is `{ id }` when\n * `emails[i]` was queued, or `{ error, code }` when it was not (unverified\n * domain, suppressed recipients, exhausted quota, …) — failed items never fail\n * the whole batch, so branch on the presence of `id` per item.\n */\nexport class Batch {\n constructor(private readonly client: Eusend) {}\n\n async send(emails: SendEmailOptions[]): Promise<EusendResponse<BatchSendResponse>> {\n const payloads = await Promise.all(emails.map(toApiPayload))\n return this.client.post<BatchSendResponse>('/emails/batch', payloads)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\nexport type DomainStatus = 'pending' | 'verified' | 'failed'\n\nexport interface DnsRecord {\n type: string\n name: string\n value: string\n /** MX records only. */\n priority?: number\n /**\n * `authentication` — required before the domain can send.\n * `policy` — recommended; absence weakens but does not block.\n * `alignment` — optional; publishing all of them enables Return-Path SPF alignment.\n */\n purpose?: string\n description?: string\n}\n\nexport interface CreateDomainResponse {\n id: string\n name: string\n /**\n * Every record to publish, in presentation order. Prefer this over the individual\n * keys below — it is the only place the optional Return-Path alignment records appear.\n */\n records: DnsRecord[]\n dkim: DnsRecord\n dmarc: DnsRecord\n}\n\nexport interface DomainListItem {\n id: string\n name: string\n status: DomainStatus\n createdAt: string\n}\n\n/** Whether a verification chain is polling DNS for this domain right now. */\nexport interface DomainVerification {\n running: boolean\n /** When the running chain started, or null when none is. */\n startedAt: string | null\n}\n\n/**\n * What the last unmatched DNS check found, when it found a mistake rather than an absence.\n *\n * `code` is the mistake: `doubled_domain` (the record sits under the domain twice, because the\n * control panel appends it to whatever you type), `truncated_key` (the value was cut at the\n * 255-character limit for a single DNS string instead of being split into two), `foreign_key`\n * (a DKIM key we did not issue is published at the selector), `quoted_value`, `multiple_records`,\n * `cname_at_selector`. New codes may be added, so treat an unknown one as generic.\n */\nexport interface DomainDiagnostic {\n code: string\n /** The name the record was actually found at, for `doubled_domain`. */\n foundAt?: string\n /** How much of the key is published, and how much there is, for `truncated_key`. */\n publishedChars?: number\n expectedChars?: number\n /** Where the CNAME points, for `cname_at_selector`. */\n target?: string\n /** The DNS host serving the zone, when its nameservers named one we recognise. */\n provider?: {\n id: string\n label: string\n /** Path to the guide for this panel on eusend.dev, or null where there is none. */\n guide: string | null\n }\n}\n\nexport interface Domain {\n id: string\n name: string\n dkimPublicKey: string\n dkimSelector: string\n status: DomainStatus\n createdAt: string\n verifiedAt: string | null\n verification: DomainVerification\n /** Null while nothing is wrong beyond the records not having propagated yet. */\n diagnostic: DomainDiagnostic | null\n}\n\nexport class Domains {\n constructor(private readonly client: Eusend) {}\n\n create(name: string): Promise<EusendResponse<CreateDomainResponse>> {\n return this.client.post<CreateDomainResponse>('/domains', { name })\n }\n\n list(): Promise<EusendResponse<DomainListItem[]>> {\n return this.client.get<DomainListItem[]>('/domains')\n }\n\n get(id: string): Promise<EusendResponse<Domain>> {\n return this.client.get<Domain>(`/domains/${id}`)\n }\n\n delete(id: string): Promise<EusendResponse<{ message: string }>> {\n return this.client.delete<{ message: string }>(`/domains/${id}`)\n }\n\n verify(id: string): Promise<EusendResponse<{ message: string }>> {\n return this.client.post<{ message: string }>(`/domains/${id}/verify`)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\n/**\n * What a key may reach. `full_access` is every resource; `sending_access` is limited to\n * sending email (and rescheduling or canceling a scheduled send).\n */\nexport type ApiKeyPermission = 'full_access' | 'sending_access'\n\nexport interface CreateApiKeyOptions {\n name: string\n testMode?: boolean\n /** Defaults to `full_access`. */\n permission?: ApiKeyPermission\n /**\n * Restrict the key to sending from a single domain. Only valid together with\n * `permission: 'sending_access'`; omit for any verified domain.\n */\n domainId?: string\n}\n\nexport interface CreateApiKeyResponse {\n id: string\n name: string\n key: string\n prefix: string\n testMode: boolean\n permission: ApiKeyPermission\n domainId: string | null\n domainName: string | null\n createdAt: string\n}\n\nexport interface ApiKey {\n id: string\n name: string\n prefix: string\n testMode: boolean\n permission: ApiKeyPermission\n domainId: string | null\n domainName: string | null\n createdAt: string\n lastUsedAt: string | null\n}\n\ntype CreateApiKeyApiResponse = {\n id: string\n name: string\n key: string\n prefix: string\n test_mode: boolean\n permission: ApiKeyPermission\n domain_id: string | null\n domain_name: string | null\n created_at: string\n}\n\nexport class ApiKeys {\n constructor(private readonly client: Eusend) {}\n\n async create(options: CreateApiKeyOptions): Promise<EusendResponse<CreateApiKeyResponse>> {\n const res = await this.client.post<CreateApiKeyApiResponse>('/api-keys', {\n name: options.name,\n test_mode: options.testMode ?? false,\n permission: options.permission ?? 'full_access',\n ...(options.domainId ? { domain_id: options.domainId } : {}),\n })\n if (res.error) return res\n return {\n data: {\n id: res.data.id,\n name: res.data.name,\n key: res.data.key,\n prefix: res.data.prefix,\n testMode: res.data.test_mode,\n permission: res.data.permission,\n domainId: res.data.domain_id,\n domainName: res.data.domain_name,\n createdAt: res.data.created_at,\n },\n error: null,\n headers: res.headers,\n }\n }\n\n list(): Promise<EusendResponse<ApiKey[]>> {\n return this.client.get<ApiKey[]>('/api-keys')\n }\n\n delete(id: string): Promise<EusendResponse<{ message: string }>> {\n return this.client.delete<{ message: string }>(`/api-keys/${id}`)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\nexport type ContactStatus = 'subscribed' | 'unsubscribed'\n\nexport interface Audience {\n id: string\n name: string\n organizationId: string\n createdAt: string\n updatedAt: string\n}\n\nexport interface AudienceListItem {\n id: string\n name: string\n createdAt: string\n contactCount: number\n}\n\nexport interface Contact {\n id: string\n audienceId: string\n email: string\n firstName: string | null\n lastName: string | null\n /** Custom properties, available as `{{key}}` in a broadcast body. */\n properties: Record<string, string>\n status: ContactStatus\n unsubscribedAt: string | null\n createdAt: string\n updatedAt: string\n}\n\nexport interface CreateContactOptions {\n email: string\n firstName?: string\n lastName?: string\n /**\n * Custom properties, merged into the `{{variable}}` map when a broadcast renders, so\n * `{ plan: 'pro' }` makes `{{plan}}` resolve to `pro`.\n *\n * Values are strings; keys are lowercase letters, digits and underscores, starting with\n * a letter (at most 40 characters, 20 properties per contact). `email`, `name`,\n * `first_name`, `last_name` and `full_name` are built in and cannot be used.\n *\n * Sending this REPLACES the contact's properties. Omitting it on `createContact` clears\n * them; omitting it on `updateContact` leaves them untouched.\n */\n properties?: Record<string, string>\n}\n\nexport interface UpdateContactOptions {\n firstName?: string\n lastName?: string\n unsubscribed?: boolean\n /** Replaces the contact's custom properties. Omit to leave them unchanged; pass `{}` to\n * clear them. See {@link CreateContactOptions.properties} for the naming rules. */\n properties?: Record<string, string>\n}\n\nexport interface ListContactsOptions {\n limit?: number\n cursor?: string\n search?: string\n subscribed?: boolean\n}\n\nexport interface ListContactsResponse {\n data: Contact[]\n nextCursor: string | null\n}\n\n/**\n * A contact in a bulk import. Extends the single-create shape with the two fields that\n * only make sense when migrating a list in from somewhere else.\n */\nexport interface BatchContactOptions extends CreateContactOptions {\n /**\n * Mark the contact as opted out, so a list moved from another provider keeps its\n * unsubscribes. An import can only ever ADD an opt-out: passing `false` will not\n * re-subscribe someone who has already unsubscribed. Use `updateContact` for that,\n * one contact at a time.\n */\n unsubscribed?: boolean\n /** Original signup time (ISO 8601). Applied on insert only — an existing contact\n * keeps the date it already has. */\n createdAt?: string\n /**\n * Unlike `createContact`, an import MERGES properties into whatever the contact already\n * has — a CSV carrying only `plan` will not drop a `company` an earlier import set. To\n * replace the whole object, use `updateContact`.\n */\n properties?: Record<string, string>\n}\n\nexport interface BatchCreateContactsOptions {\n contacts: BatchContactOptions[]\n}\n\nexport class Audiences {\n constructor(private readonly client: Eusend) {}\n\n create(name: string): Promise<EusendResponse<Audience>> {\n return this.client.post<Audience>('/audiences', { name })\n }\n\n async list(): Promise<EusendResponse<AudienceListItem[]>> {\n const res = await this.client.get<{ data: AudienceListItem[] }>('/audiences')\n if (res.error) return res\n return { data: res.data.data, error: null, headers: res.headers }\n }\n\n delete(id: string): Promise<EusendResponse<Record<string, never>>> {\n return this.client.delete<Record<string, never>>(`/audiences/${id}`)\n }\n\n createContact(\n audienceId: string,\n options: CreateContactOptions,\n ): Promise<EusendResponse<Contact>> {\n return this.client.post<Contact>(`/audiences/${audienceId}/contacts`, {\n email: options.email,\n first_name: options.firstName,\n last_name: options.lastName,\n properties: options.properties,\n })\n }\n\n async listContacts(\n audienceId: string,\n options: ListContactsOptions = {},\n ): Promise<EusendResponse<ListContactsResponse>> {\n const params = new URLSearchParams()\n if (options.limit != null) params.set('limit', String(options.limit))\n if (options.cursor) params.set('cursor', options.cursor)\n if (options.search) params.set('search', options.search)\n if (options.subscribed != null) params.set('subscribed', String(options.subscribed))\n const qs = params.toString()\n return this.client.get<ListContactsResponse>(\n qs ? `/audiences/${audienceId}/contacts?${qs}` : `/audiences/${audienceId}/contacts`,\n )\n }\n\n getContact(audienceId: string, contactId: string): Promise<EusendResponse<Contact>> {\n return this.client.get<Contact>(`/audiences/${audienceId}/contacts/${contactId}`)\n }\n\n updateContact(\n audienceId: string,\n contactId: string,\n options: UpdateContactOptions,\n ): Promise<EusendResponse<Contact>> {\n return this.client.patch<Contact>(`/audiences/${audienceId}/contacts/${contactId}`, {\n first_name: options.firstName,\n last_name: options.lastName,\n unsubscribed: options.unsubscribed,\n properties: options.properties,\n })\n }\n\n deleteContact(\n audienceId: string,\n contactId: string,\n ): Promise<EusendResponse<Record<string, never>>> {\n return this.client.delete<Record<string, never>>(\n `/audiences/${audienceId}/contacts/${contactId}`,\n )\n }\n\n /**\n * Upsert up to 1000 contacts in one call. Addresses are lowercased and\n * de-duplicated server-side; `count` is the number of rows written and\n * `duplicates` how many repeated addresses were collapsed to get there.\n */\n /**\n * Delete up to 1,000 contacts from an audience by id.\n *\n * `deleted` may be lower than the number of ids sent — an id may already be gone, or\n * may belong to another audience — so a retry after a dropped response settles at 0\n * rather than failing.\n *\n * This is not an unsubscribe. It removes them from the audience without adding them to\n * the suppression list; use `updateContact({ unsubscribed: true })` to stop mailing\n * somebody while keeping the record.\n */\n batchDeleteContacts(\n audienceId: string,\n contactIds: string[],\n ): Promise<EusendResponse<{ deleted: number }>> {\n return this.client.post<{ deleted: number }>(\n `/audiences/${audienceId}/contacts/batch-delete`,\n { contact_ids: contactIds },\n )\n }\n\n batchCreateContacts(\n audienceId: string,\n options: BatchCreateContactsOptions,\n ): Promise<EusendResponse<{ count: number; duplicates: number }>> {\n return this.client.post<{ count: number; duplicates: number }>(\n `/audiences/${audienceId}/contacts/batch`,\n {\n contacts: options.contacts.map((c) => ({\n email: c.email,\n first_name: c.firstName,\n last_name: c.lastName,\n unsubscribed: c.unsubscribed,\n created_at: c.createdAt,\n properties: c.properties,\n })),\n },\n )\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\n/**\n * A declared property's type. Values are carried and rendered as strings either way —\n * `number` buys a write-time check, not arithmetic or locale formatting.\n */\nexport type ContactPropertyType = 'string' | 'number'\n\nexport interface ContactProperty {\n id: string\n key: string\n type: ContactPropertyType\n /** Substituted into `{{key}}` for contacts that carry no value of their own. `null`\n * renders empty, which is what an unset property did before the registry existed. */\n fallbackValue: string | null\n createdAt: string\n updatedAt: string\n}\n\nexport interface CreateContactPropertyOptions {\n /** Lowercase letters, digits and underscores, starting with a letter; at most 40\n * characters. `email`, `name`, `first_name`, `last_name` and `full_name` are built in\n * and cannot be declared. */\n key: string\n /** Defaults to `string`. */\n type?: ContactPropertyType\n fallbackValue?: string | null\n}\n\nexport interface UpdateContactPropertyOptions {\n /** The only mutable field. `key` and `type` are fixed at creation: a rename would have\n * to rewrite every contact and every broadcast body spelling `{{old_key}}`, so changing\n * either is a delete and a create. */\n fallbackValue: string | null\n}\n\nexport interface DeleteContactPropertyResponse {\n deleted: true\n /** How many contacts had the key stripped from them. */\n contactsUpdated: number\n}\n\n/**\n * The organization's custom contact properties — the schema behind the `properties` bag\n * each contact carries.\n *\n * Declaring a property is optional. A property arriving on a contact write that has never\n * been declared registers itself as a `string`, so an existing integration needs no\n * changes. Declaring one up front is what buys a type check and a fallback value.\n */\nexport class ContactProperties {\n constructor(private readonly client: Eusend) {}\n\n create(options: CreateContactPropertyOptions): Promise<EusendResponse<ContactProperty>> {\n return this.client.post<ContactProperty>('/contact-properties', {\n key: options.key,\n type: options.type,\n fallback_value: options.fallbackValue,\n })\n }\n\n /** Every property the organization has defined. Unpaginated — the registry is capped at\n * 100 entries, and a variable picker wants all of them. */\n async list(): Promise<EusendResponse<ContactProperty[]>> {\n const res = await this.client.get<{ data: ContactProperty[] }>('/contact-properties')\n if (res.error) return res\n return { data: res.data.data, error: null, headers: res.headers }\n }\n\n get(id: string): Promise<EusendResponse<ContactProperty>> {\n return this.client.get<ContactProperty>(`/contact-properties/${id}`)\n }\n\n update(\n id: string,\n options: UpdateContactPropertyOptions,\n ): Promise<EusendResponse<ContactProperty>> {\n return this.client.patch<ContactProperty>(`/contact-properties/${id}`, {\n fallback_value: options.fallbackValue,\n })\n }\n\n /**\n * Delete a property definition AND strip the key from every contact in the organization.\n *\n * Destructive and not undoable. Leaving the values in place was the alternative, and a\n * worse one: the property would keep rendering in broadcasts, and the next contact write\n * carrying that key would register it again.\n */\n delete(id: string): Promise<EusendResponse<DeleteContactPropertyResponse>> {\n return this.client.delete<DeleteContactPropertyResponse>(`/contact-properties/${id}`)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\n/** What a contact who has never expressed a preference receives. Fixed at creation. */\nexport type TopicDefaultSubscription = 'opt_in' | 'opt_out'\n\n/** Whether the topic is listed on the unsubscribe page to a contact who is not opted in. */\nexport type TopicVisibility = 'public' | 'private'\n\nexport interface Topic {\n id: string\n name: string\n description: string | null\n defaultSubscription: TopicDefaultSubscription\n visibility: TopicVisibility\n /** Contacts who explicitly opted in. Present on list and create, not on get. */\n subscriberCount?: number\n createdAt: string\n updatedAt: string\n}\n\nexport interface CreateTopicOptions {\n name: string\n /** `opt_in` reaches everyone until they leave; `opt_out` reaches nobody until they join.\n * Cannot be changed afterwards. */\n defaultSubscription: TopicDefaultSubscription\n description?: string | null\n /** Defaults to `private`. */\n visibility?: TopicVisibility\n}\n\n/** `defaultSubscription` is absent deliberately — it is fixed at creation. */\nexport interface UpdateTopicOptions {\n name?: string\n description?: string | null\n visibility?: TopicVisibility\n}\n\nexport interface DeleteTopicResponse {\n id: string\n deleted: true\n}\n\nexport interface TopicSubscriptionResponse {\n topicId: string\n contactId: string\n subscribed: boolean\n}\n\nexport interface ClearTopicSubscriptionResponse {\n topicId: string\n contactId: string\n deleted: true\n}\n\nexport class Topics {\n constructor(private readonly client: Eusend) {}\n\n create(options: CreateTopicOptions): Promise<EusendResponse<Topic>> {\n return this.client.post<Topic>('/topics', {\n name: options.name,\n default_subscription: options.defaultSubscription,\n description: options.description,\n visibility: options.visibility,\n })\n }\n\n /** Every topic the organization has defined. Unpaginated — the list is capped at 100,\n * and both the composer's picker and the unsubscribe page want all of it. */\n async list(): Promise<EusendResponse<Topic[]>> {\n const res = await this.client.get<{ data: Topic[] }>('/topics')\n if (res.error) return res\n return { data: res.data.data, error: null, headers: res.headers }\n }\n\n get(id: string): Promise<EusendResponse<Topic>> {\n return this.client.get<Topic>(`/topics/${id}`)\n }\n\n update(id: string, options: UpdateTopicOptions): Promise<EusendResponse<Topic>> {\n return this.client.patch<Topic>(`/topics/${id}`, {\n name: options.name,\n description: options.description,\n visibility: options.visibility,\n })\n }\n\n /** Deletes the topic and every stored preference for it. A draft or scheduled broadcast\n * scoped to it widens back to its whole audience. */\n delete(id: string): Promise<EusendResponse<DeleteTopicResponse>> {\n return this.client.delete<DeleteTopicResponse>(`/topics/${id}`)\n }\n\n /** Record an explicit preference for one contact. */\n subscribe(\n topicId: string,\n contactId: string,\n subscribed = true,\n ): Promise<EusendResponse<TopicSubscriptionResponse>> {\n return this.client.put<TopicSubscriptionResponse>(\n `/topics/${topicId}/contacts/${contactId}`,\n { subscribed },\n )\n }\n\n /**\n * Forget the contact's explicit choice, so they fall back to the topic's default.\n *\n * Different from `subscribe(id, contactId, false)`: that records \"no thanks\", this\n * records nothing at all — so on an opt-in topic the contact starts receiving it again.\n */\n clearSubscription(\n topicId: string,\n contactId: string,\n ): Promise<EusendResponse<ClearTopicSubscriptionResponse>> {\n return this.client.delete<ClearTopicSubscriptionResponse>(\n `/topics/${topicId}/contacts/${contactId}`,\n )\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\nimport { renderReactEmail, type ReactEmailElement } from './react-render'\n\ninterface TemplateHtmlOrReact {\n /**\n * A React Email component. The SDK renders it to HTML locally before sending.\n * Requires `@react-email/render` and `react` as peer dependencies.\n * Ignored when `html` is also provided.\n */\n react?: ReactEmailElement\n}\n\nexport interface CreateTemplateOptions extends TemplateHtmlOrReact {\n name: string\n subject: string\n html?: string\n}\n\nexport interface UpdateTemplateOptions extends TemplateHtmlOrReact {\n name?: string\n subject?: string\n html?: string\n}\n\nexport interface Template {\n id: string\n name: string\n subject: string\n html: string | null\n reactSource: string | null\n createdAt: string\n updatedAt: string\n}\n\nexport interface TemplateListItem {\n id: string\n name: string\n subject: string\n createdAt: string\n updatedAt: string\n}\n\nasync function resolveTemplateHtml(\n options: TemplateHtmlOrReact & { html?: string },\n): Promise<string | undefined> {\n if (options.html) return options.html\n if (options.react) return renderReactEmail(options.react)\n return undefined\n}\n\nexport class Templates {\n constructor(private readonly client: Eusend) {}\n\n async create(options: CreateTemplateOptions): Promise<EusendResponse<Template>> {\n const html = await resolveTemplateHtml(options)\n if (!html) {\n return {\n data: null,\n error: {\n message: 'Either html or react is required',\n statusCode: null,\n name: 'VALIDATION_ERROR',\n },\n headers: null,\n }\n }\n return this.client.post<Template>('/templates', {\n name: options.name,\n subject: options.subject,\n html,\n })\n }\n\n async list(): Promise<EusendResponse<TemplateListItem[]>> {\n const res = await this.client.get<{ data: TemplateListItem[] }>('/templates')\n if (res.error) return res\n return { data: res.data.data, error: null, headers: res.headers }\n }\n\n get(id: string): Promise<EusendResponse<Template>> {\n return this.client.get<Template>(`/templates/${id}`)\n }\n\n async update(id: string, options: UpdateTemplateOptions): Promise<EusendResponse<Template>> {\n const html = await resolveTemplateHtml(options)\n return this.client.patch<Template>(`/templates/${id}`, {\n name: options.name,\n subject: options.subject,\n html,\n })\n }\n\n delete(id: string): Promise<EusendResponse<Record<string, never>>> {\n return this.client.delete<Record<string, never>>(`/templates/${id}`)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\nexport type WebhookEvent =\n | 'email.sent'\n | 'email.delivered'\n | 'email.bounced'\n | 'email.complained'\n | 'email.opened'\n | 'email.clicked'\n | '*'\n\nexport interface CreateWebhookOptions {\n url: string\n events: WebhookEvent[]\n}\n\nexport interface UpdateWebhookOptions {\n url?: string\n events?: WebhookEvent[]\n}\n\nexport interface WebhookDelivery {\n id: string\n webhookId: string\n emailId: string | null\n eventType: string\n payload: Record<string, unknown>\n status: 'pending' | 'success' | 'failed'\n responseStatus: number | null\n attempts: number\n createdAt: string\n lastAttemptAt: string | null\n}\n\nexport interface Webhook {\n id: string\n url: string\n events: WebhookEvent[]\n createdAt: string\n}\n\nexport interface WebhookWithDeliveries extends Webhook {\n deliveries: WebhookDelivery[]\n}\n\nexport interface CreateWebhookResponse extends Webhook {\n secret: string\n}\n\nexport class Webhooks {\n constructor(private readonly client: Eusend) {}\n\n create(options: CreateWebhookOptions): Promise<EusendResponse<CreateWebhookResponse>> {\n return this.client.post<CreateWebhookResponse>('/webhooks', {\n url: options.url,\n events: options.events,\n })\n }\n\n async list(): Promise<EusendResponse<Webhook[]>> {\n const res = await this.client.get<{ data: Webhook[] }>('/webhooks')\n if (res.error) return res\n return { data: res.data.data, error: null, headers: res.headers }\n }\n\n get(id: string): Promise<EusendResponse<WebhookWithDeliveries>> {\n return this.client.get<WebhookWithDeliveries>(`/webhooks/${id}`)\n }\n\n update(id: string, options: UpdateWebhookOptions): Promise<EusendResponse<Webhook>> {\n return this.client.patch<Webhook>(`/webhooks/${id}`, {\n url: options.url,\n events: options.events,\n })\n }\n\n delete(id: string): Promise<EusendResponse<Record<string, never>>> {\n return this.client.delete<Record<string, never>>(`/webhooks/${id}`)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\nimport { renderReactEmail, type ReactEmailElement } from './react-render'\n\n/**\n * `held` is a list send stopped part-way pending review. Unlike `paused` it cannot be\n * resumed by sending again — `send()` returns BROADCAST_HELD until the review clears.\n */\nexport type BroadcastStatus =\n 'draft' | 'scheduled' | 'sending' | 'sent' | 'paused' | 'held' | 'cancelled'\n\nexport interface CreateBroadcastOptions {\n name: string\n audienceId: string\n /** Narrows the audience to the contacts subscribed to this topic. Omit to send to all\n * of it. */\n topicId?: string\n /**\n * Sender address. Accepts a bare email (`onboarding@eusend.dev`) or a display-name\n * form (`Acme <onboarding@eusend.dev>`). The domain must be verified on your account.\n */\n from: string\n subject: string\n html?: string\n /**\n * A React Email component. The SDK renders it to HTML locally before sending —\n * the JSX source never travels over the wire. Requires `@react-email/render`\n * and `react` as peer dependencies. Ignored when `html` is also provided.\n */\n react?: ReactEmailElement\n templateId?: string\n templateVariables?: Record<string, string>\n /**\n * Embed the open-tracking pixel for this broadcast. Omit to use your organization's\n * default (Settings → General → Email tracking); `false` always wins over it.\n */\n trackOpens?: boolean\n /**\n * Rewrite links so clicks are recorded. Omit to use your organization's default;\n * `false` leaves the original URLs untouched in the delivered mail.\n */\n trackClicks?: boolean\n}\n\nexport interface UpdateBroadcastOptions {\n name?: string\n audienceId?: string\n /** Pass null to clear the topic and widen the send back to the whole audience. */\n topicId?: string | null\n from?: string\n subject?: string\n html?: string\n /**\n * See `react` on CreateBroadcastOptions. Rendered to HTML locally before sending.\n */\n react?: ReactEmailElement\n templateId?: string | null\n templateVariables?: Record<string, string> | null\n scheduledAt?: string | null\n /**\n * Embed the open-tracking pixel for this broadcast. Omit to use your organization's\n * default (Settings → General → Email tracking); `false` always wins over it.\n */\n trackOpens?: boolean\n /**\n * Rewrite links so clicks are recorded. Omit to use your organization's default;\n * `false` leaves the original URLs untouched in the delivered mail.\n */\n trackClicks?: boolean\n}\n\nexport interface SendBroadcastOptions {\n scheduledAt?: string\n}\n\nexport interface Broadcast {\n id: string\n organizationId: string\n name: string\n status: BroadcastStatus\n /** Null when the associated audience has been deleted. */\n audienceId: string | null\n /** The topic this broadcast is scoped to, or null for the whole audience. */\n topicId: string | null\n fromAddress: string\n replyTo: string | null\n subject: string\n html: string | null\n reactSource: string | null\n editorJson: Record<string, unknown> | null\n templateId: string | null\n templateVariables: Record<string, string> | null\n heldReason: string | null\n scheduledAt: string | null\n startedAt: string | null\n completedAt: string | null\n recipientCount: number | null\n sentCount: number | null\n trackOpens: boolean\n trackClicks: boolean\n createdAt: string\n updatedAt: string\n}\n\nexport interface BroadcastListItem {\n id: string\n name: string\n status: BroadcastStatus\n /** Null when the associated audience has been deleted. */\n audienceId: string | null\n topicId: string | null\n topicName: string | null\n fromAddress: string\n subject: string\n recipientCount: number | null\n sentCount: number | null\n scheduledAt: string | null\n startedAt: string | null\n completedAt: string | null\n createdAt: string\n audienceName: string | null\n}\n\nexport interface BroadcastDetail extends Broadcast {\n stats: Record<string, number>\n}\n\nexport interface TestBroadcastOptions {\n /**\n * Up to 5 addresses, each on a domain verified on your account. A test send delivers\n * real mail without the paid-plan gate that `send()` carries, so it is restricted to\n * inboxes you have already proved you control; anything else returns\n * `DOMAIN_NOT_VERIFIED`.\n */\n to: string[]\n}\n\nexport interface TestBroadcastResponse {\n id: string\n /** The addresses actually mailed, lowercased and de-duplicated. */\n sentTo: string[]\n /** One email id per recipient, for looking the delivery up in the logs. */\n emailIds: string[]\n}\n\nexport interface SendBroadcastResponse {\n id: string\n status: 'sending' | 'scheduled'\n scheduledAt: string | null\n}\n\nasync function resolveBroadcastHtml(options: {\n html?: string\n react?: ReactEmailElement\n}): Promise<string | undefined> {\n if (options.html) return options.html\n if (options.react) return renderReactEmail(options.react)\n return undefined\n}\n\nexport class Broadcasts {\n constructor(private readonly client: Eusend) {}\n\n async create(options: CreateBroadcastOptions): Promise<EusendResponse<Broadcast>> {\n const html = await resolveBroadcastHtml(options)\n return this.client.post<Broadcast>('/broadcasts', {\n name: options.name,\n audience_id: options.audienceId,\n topic_id: options.topicId,\n from: options.from,\n subject: options.subject,\n html,\n template_id: options.templateId,\n template_variables: options.templateVariables,\n track_opens: options.trackOpens,\n track_clicks: options.trackClicks,\n })\n }\n\n async list(): Promise<EusendResponse<BroadcastListItem[]>> {\n const res = await this.client.get<{ data: BroadcastListItem[] }>('/broadcasts')\n if (res.error) return res\n return { data: res.data.data, error: null, headers: res.headers }\n }\n\n get(id: string): Promise<EusendResponse<BroadcastDetail>> {\n return this.client.get<BroadcastDetail>(`/broadcasts/${id}`)\n }\n\n async update(id: string, options: UpdateBroadcastOptions): Promise<EusendResponse<Broadcast>> {\n const html = await resolveBroadcastHtml(options)\n return this.client.patch<Broadcast>(`/broadcasts/${id}`, {\n name: options.name,\n audience_id: options.audienceId,\n topic_id: options.topicId,\n from: options.from,\n subject: options.subject,\n html,\n template_id: options.templateId,\n template_variables: options.templateVariables,\n scheduled_at: options.scheduledAt,\n track_opens: options.trackOpens,\n track_clicks: options.trackClicks,\n })\n }\n\n async send(\n id: string,\n options: SendBroadcastOptions = {},\n ): Promise<EusendResponse<SendBroadcastResponse>> {\n // This endpoint is the one broadcast response that comes back snake_cased, so\n // map it rather than exposing a `scheduledAt` that is always undefined.\n const res = await this.client.post<{\n id: string\n status: 'sending' | 'scheduled'\n scheduled_at: string | null\n }>(`/broadcasts/${id}/send`, {\n scheduled_at: options.scheduledAt,\n })\n if (res.error) return res\n return {\n data: { id: res.data.id, status: res.data.status, scheduledAt: res.data.scheduled_at },\n error: null,\n headers: res.headers,\n }\n }\n\n /**\n * Send yourself a copy before the campaign goes out — the real message through the real\n * sending path, so it shows what a recipient will see.\n *\n * Works on every plan including Free, unlike `send()`. It costs daily and monthly quota\n * like any other send, and does NOT move the broadcast's status: the campaign stays a\n * draft no matter how many tests you send.\n *\n * Requires a LIVE api key. \"Test\" here means a dress rehearsal, not a sandbox — a\n * `eu_test_` key is refused because the mail really is delivered.\n */\n async test(\n id: string,\n options: TestBroadcastOptions,\n ): Promise<EusendResponse<TestBroadcastResponse>> {\n // Snake-cased on the wire, like the send() response above.\n const res = await this.client.post<{\n id: string\n sent_to: string[]\n email_ids: string[]\n }>(`/broadcasts/${id}/test`, { to: options.to })\n if (res.error) return res\n return {\n data: { id: res.data.id, sentTo: res.data.sent_to, emailIds: res.data.email_ids },\n error: null,\n headers: res.headers,\n }\n }\n\n cancel(id: string): Promise<EusendResponse<Broadcast>> {\n return this.client.post<Broadcast>(`/broadcasts/${id}/cancel`)\n }\n\n delete(id: string): Promise<EusendResponse<Record<string, never>>> {\n return this.client.delete<Record<string, never>>(`/broadcasts/${id}`)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\nexport type SuppressionReason = 'bounce' | 'complaint' | 'manual'\n\nexport interface SuppressionEntry {\n id: string\n email: string\n reason: SuppressionReason\n created_at: string\n}\n\nexport interface ListSuppressionsOptions {\n /** Filter to addresses containing this substring. Pass a domain (\"@acme.com\") to see every suppressed address there. */\n email?: string\n reason?: SuppressionReason\n limit?: number\n cursor?: string\n}\n\nexport interface ListSuppressionsResponse {\n data: SuppressionEntry[]\n next_cursor: string | null\n}\n\nexport interface CreateSuppressionOptions {\n email: string\n /** Defaults to 'manual'. An add never overwrites the reason an address is already suppressed for. */\n reason?: SuppressionReason\n}\n\n/** An item in an import — a bare address, or an address with the reason it was suppressed. */\nexport type SuppressionImportItem = string | { email: string; reason?: SuppressionReason }\n\nexport interface ImportSuppressionsResponse {\n /** Entries written. */\n count: number\n /** Entries that were already on the list. */\n already_suppressed: number\n /** Repeated addresses in the payload, collapsed before the write. */\n duplicates: number\n}\n\n/**\n * The addresses your organization will not send to.\n *\n * Hard bounces and spam complaints are added automatically; these methods cover the\n * addresses you manage yourself. Suppression applies to live sending only — test-mode\n * keys can read the list but not modify it.\n */\nexport class Suppressions {\n constructor(private readonly client: Eusend) {}\n\n list(options: ListSuppressionsOptions = {}): Promise<EusendResponse<ListSuppressionsResponse>> {\n const params = new URLSearchParams()\n if (options.email) params.set('email', options.email)\n if (options.reason) params.set('reason', options.reason)\n if (options.limit != null) params.set('limit', String(options.limit))\n if (options.cursor) params.set('cursor', options.cursor)\n const qs = params.toString()\n return this.client.get<ListSuppressionsResponse>(qs ? `/suppressions?${qs}` : '/suppressions')\n }\n\n /**\n * Suppress an address. If it is already suppressed the existing entry is returned\n * unchanged — a manual add never rewrites a real bounce or complaint.\n */\n create(options: CreateSuppressionOptions): Promise<EusendResponse<SuppressionEntry>> {\n return this.client.post<SuppressionEntry>('/suppressions', {\n email: options.email,\n reason: options.reason,\n })\n }\n\n /**\n * Import up to 1000 addresses in one call — for carrying a suppression list over from\n * another provider before your first send. Items may be bare addresses or objects.\n */\n import(emails: SuppressionImportItem[]): Promise<EusendResponse<ImportSuppressionsResponse>> {\n return this.client.post<ImportSuppressionsResponse>('/suppressions/batch', { emails })\n }\n\n /**\n * Un-suppress by entry id or by address, making the address sendable again.\n *\n * Removing an address that hard-bounced or complained is what damages a sender's\n * reputation when done in bulk — remove an entry when the address was fixed or the\n * complaint was a mistake, not to retry a failing list.\n */\n remove(idOrEmail: string): Promise<EusendResponse<{ deleted: number }>> {\n return this.client.delete<{ deleted: number }>(`/suppressions/${encodeURIComponent(idOrEmail)}`)\n }\n\n /** The whole list as CSV (`email,reason,created_at`), for backup or migration. */\n export(): Promise<EusendResponse<string>> {\n return this.client.fetchRequest<string>('/suppressions/export', { method: 'GET' }, {}, 'text')\n }\n}\n","import type { EusendError, EusendResponse } from './interfaces'\nimport { Emails } from './emails'\nimport { Batch } from './batch'\nimport { Domains } from './domains'\nimport { ApiKeys } from './api-keys'\nimport { Audiences } from './audiences'\nimport { ContactProperties } from './contact-properties'\nimport { Topics } from './topics'\nimport { Templates } from './templates'\nimport { Webhooks } from './webhooks'\nimport { Broadcasts } from './broadcasts'\nimport { Suppressions } from './suppressions'\n\nconst DEFAULT_BASE_URL = 'https://api.eusend.dev'\nconst SDK_VERSION = '0.18.0'\n\nexport interface EusendOptions {\n baseUrl?: string\n}\n\nexport class Eusend {\n readonly baseUrl: string\n private readonly apiKey: string\n\n readonly emails: Emails\n /** Batch sending — `client.batch.send([...])`. Mirrors Resend's `resend.batch.send()`. */\n readonly batch: Batch\n readonly domains: Domains\n readonly apiKeys: ApiKeys\n readonly audiences: Audiences\n /** The org's declared contact properties — `client.contactProperties.list()`. */\n readonly contactProperties: ContactProperties\n /** Subscription topics — `client.topics.list()`. */\n readonly topics: Topics\n readonly templates: Templates\n readonly webhooks: Webhooks\n readonly broadcasts: Broadcasts\n readonly suppressions: Suppressions\n\n constructor(key?: string, options?: EusendOptions) {\n const apiKey =\n key ?? (typeof process !== 'undefined' ? process.env['EUSEND_API_KEY'] : undefined)\n if (!apiKey) {\n throw new Error(\n 'Missing Eusend API key. Pass it to the constructor or set the EUSEND_API_KEY environment variable.',\n )\n }\n this.apiKey = apiKey\n this.baseUrl = options?.baseUrl ?? DEFAULT_BASE_URL\n\n this.emails = new Emails(this)\n this.batch = new Batch(this)\n this.domains = new Domains(this)\n this.apiKeys = new ApiKeys(this)\n this.audiences = new Audiences(this)\n this.contactProperties = new ContactProperties(this)\n this.topics = new Topics(this)\n this.templates = new Templates(this)\n this.webhooks = new Webhooks(this)\n this.broadcasts = new Broadcasts(this)\n this.suppressions = new Suppressions(this)\n }\n\n async fetchRequest<T>(\n path: string,\n init: RequestInit = {},\n extraHeaders: Record<string, string> = {},\n // Not every successful endpoint answers with JSON — the suppression export returns\n // CSV. Parsing that as JSON throws inside the try below, which would surface a\n // perfectly good download as \"Network request failed\".\n parse: 'json' | 'text' = 'json',\n ): Promise<EusendResponse<T>> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': `eusend-node/${SDK_VERSION}`,\n ...extraHeaders,\n }\n\n try {\n const res = await fetch(`${this.baseUrl}${path}`, { ...init, headers })\n const responseHeaders = Object.fromEntries(res.headers.entries())\n\n if (!res.ok) {\n let error: EusendError\n try {\n const json = (await res.json()) as { error?: string; code?: string }\n error = {\n message: json.error ?? 'Unknown error',\n statusCode: res.status,\n name: (json.code as EusendError['name']) ?? 'INTERNAL_ERROR',\n }\n } catch {\n error = { message: 'Request failed', statusCode: res.status, name: 'INTERNAL_ERROR' }\n }\n return { data: null, error, headers: responseHeaders }\n }\n\n if (res.status === 204 || res.headers.get('content-length') === '0') {\n return { data: {} as T, error: null, headers: responseHeaders }\n }\n\n const data = (parse === 'text' ? await res.text() : await res.json()) as T\n return { data, error: null, headers: responseHeaders }\n } catch {\n return {\n data: null,\n error: {\n message: 'Network request failed. The request could not be resolved.',\n statusCode: null,\n name: 'application_error',\n },\n headers: null,\n }\n }\n }\n\n get<T>(path: string, extraHeaders?: Record<string, string>): Promise<EusendResponse<T>> {\n return this.fetchRequest<T>(path, { method: 'GET' }, extraHeaders)\n }\n\n post<T>(\n path: string,\n body?: unknown,\n extraHeaders?: Record<string, string>,\n ): Promise<EusendResponse<T>> {\n return this.fetchRequest<T>(\n path,\n { method: 'POST', body: body != null ? JSON.stringify(body) : undefined },\n extraHeaders,\n )\n }\n\n patch<T>(path: string, body?: unknown): Promise<EusendResponse<T>> {\n return this.fetchRequest<T>(path, {\n method: 'PATCH',\n body: body != null ? JSON.stringify(body) : undefined,\n })\n }\n\n put<T>(path: string, body?: unknown): Promise<EusendResponse<T>> {\n return this.fetchRequest<T>(path, {\n method: 'PUT',\n body: body != null ? JSON.stringify(body) : undefined,\n })\n }\n\n delete<T>(path: string): Promise<EusendResponse<T>> {\n return this.fetchRequest<T>(path, { method: 'DELETE' })\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/react-render.ts","../src/emails.ts","../src/batch.ts","../src/domains.ts","../src/api-keys.ts","../src/audiences.ts","../src/contact-properties.ts","../src/topics.ts","../src/templates.ts","../src/webhooks.ts","../src/broadcasts.ts","../src/suppressions.ts","../src/eusend.ts"],"sourcesContent":["// Minimal structural type so the SDK doesn't take a hard dependency on `react`.\n// Real React elements assignable to this; users who pass `react:` are expected to\n// have `react` and `@react-email/render` installed (declared as optional peers).\nexport type ReactEmailElement = {\n readonly type: unknown\n readonly props: unknown\n readonly key: string | number | null\n}\n\nlet renderPromise: Promise<(element: ReactEmailElement) => Promise<string>> | null = null\n\nasync function getRender(): Promise<(element: ReactEmailElement) => Promise<string>> {\n if (!renderPromise) {\n renderPromise = (async () => {\n try {\n const mod = (await import('@react-email/render')) as {\n render: (element: unknown, options?: { plainText?: boolean }) => Promise<string> | string\n }\n return (element: ReactEmailElement) => Promise.resolve(mod.render(element))\n } catch {\n throw new Error(\n 'Passing `react:` requires `@react-email/render` and `react` to be installed. ' +\n 'Run: npm install @react-email/render react',\n )\n }\n })()\n }\n return renderPromise\n}\n\nexport async function renderReactEmail(element: ReactEmailElement): Promise<string> {\n const render = await getRender()\n return render(element)\n}\n","import type { Eusend } from './eusend'\nimport type { EusendErrorCode, EusendResponse } from './interfaces'\nimport { renderReactEmail, type ReactEmailElement } from './react-render'\n\nexport type EmailStatus =\n | 'queued'\n | 'scheduled'\n | 'canceled'\n | 'sending'\n | 'sent'\n | 'delivered'\n | 'bounced'\n | 'complained'\n | 'suppressed'\n | 'failed'\n\nexport type EmailEventType = 'sent' | 'delivered' | 'opened' | 'clicked' | 'bounced' | 'complained'\n\nexport interface Attachment {\n /** Name the recipient sees for the file, e.g. `invoice.pdf`. */\n filename: string\n /**\n * File contents. A base64-encoded string (sent as-is) or raw bytes\n * (`Uint8Array`/`Buffer`), which the SDK base64-encodes for you. Provide either\n * `content` or `path`, not both.\n */\n content?: string | Uint8Array\n /**\n * A URL the server fetches at send time to attach the file. Use instead of\n * `content` when the bytes live on a public URL. Provide either `content` or `path`,\n * not both.\n */\n path?: string\n /** MIME type, e.g. `application/pdf`. Inferred from the filename when omitted. */\n contentType?: string\n /**\n * Content-ID for an inline attachment. Set it to reference the file from your\n * HTML with `<img src=\"cid:<contentId>\">` instead of showing it as a download.\n */\n contentId?: string\n}\n\n/** A single tag in the `[{ name, value }]` form, for Resend-compatible payloads. */\nexport interface EmailTag {\n name: string\n value: string\n}\n\n/**\n * Labels attached to a send, used to filter your email log and to route webhook events.\n *\n * Accepts either a plain object (`{ category: 'password_reset' }`) or the\n * `[{ name, value }]` array form, so a payload written against Resend works unchanged.\n * Responses and webhook payloads always return the object form.\n *\n * Names and values may contain ASCII letters, numbers, underscores and dashes; up to 10\n * tags per email.\n */\nexport type EmailTags = Record<string, string> | EmailTag[]\n\nexport interface SendEmailOptions {\n /**\n * Sender address. Accepts a bare email (`onboarding@eusend.dev`) or a display-name\n * form (`Acme <onboarding@eusend.dev>`). The domain must be verified on your account.\n */\n from: string\n to: string | string[]\n cc?: string | string[]\n bcc?: string | string[]\n replyTo?: string | string[]\n subject?: string\n html?: string\n text?: string\n /**\n * A React Email component. The SDK renders it to HTML locally before sending\n * — the JSX source never travels over the wire. Requires `@react-email/render`\n * and `react` as peer dependencies. Ignored when `html` is also provided.\n */\n react?: ReactEmailElement\n templateId?: string\n variables?: Record<string, unknown>\n headers?: Record<string, string>\n /**\n * Labels for log filtering and webhook routing, e.g.\n * `{ category: 'password_reset', tier: 'pro' }`. Returned on every `email.*` webhook\n * event for this send.\n */\n tags?: EmailTags\n trackOpens?: boolean\n trackClicks?: boolean\n /** File attachments. Up to 20 per message, 10 MB combined. */\n attachments?: Attachment[]\n /**\n * Schedule the send for a future time, at most 30 days out. Accepts a `Date`, an\n * ISO 8601 string, or a natural-language time like `\"in 1 hour\"` or `\"tomorrow at\n * 9am\"` (parsed server-side, same as Resend). Relative phrasings resolve against the\n * server clock in UTC — pass an offset-qualified ISO string when you need an exact\n * instant. The email is created with status `scheduled`; reschedule it with\n * `emails.update()` or call `emails.cancel()` any time before it sends.\n */\n scheduledAt?: string | Date\n}\n\nexport interface SendEmailRequestOptions {\n idempotencyKey?: string\n}\n\nexport interface SendEmailResponse {\n id: string\n}\n\n/**\n * Per-item outcome of a batch send, positionally mapped to the input array:\n * `data[i]` describes `emails[i]`. Items that were queued carry `{ id }`; items\n * that could not be queued carry `{ error, code }` (e.g. an unverified sender\n * domain, all recipients suppressed, or an exhausted send quota). Branch on the\n * presence of `id`.\n */\nexport type BatchItemResult =\n { id: string; error?: never; code?: never } | { id?: never; error: string; code: EusendErrorCode }\n\nexport interface BatchSendResponse {\n data: BatchItemResult[]\n}\n\nexport interface EmailEvent {\n id: string\n type: EmailEventType\n metadata: Record<string, unknown>\n createdAt: string\n}\n\nexport interface Email {\n id: string\n from: string\n to: string[]\n cc: string[]\n bcc: string[]\n replyTo: string[]\n subject: string\n html: string | null\n text: string | null\n status: EmailStatus\n /** Always the object form, `{}` when the send carried no tags. */\n tags: Record<string, string>\n testMode: boolean\n templateId: string | null\n /** Set only for scheduled sends. */\n scheduledAt: string | null\n createdAt: string\n events: EmailEvent[]\n}\n\nexport interface UpdateEmailOptions {\n /** The new send time, at most 30 days out — a `Date`, an ISO 8601 string, or natural\n * language like `\"in 1 hour\"` (parsed server-side, same as `emails.send`). */\n scheduledAt: string | Date\n}\n\nexport interface UpdateEmailResponse {\n id: string\n status: 'scheduled'\n scheduledAt: string\n}\n\nexport interface CancelEmailResponse {\n id: string\n status: 'canceled'\n}\n\nexport interface EmailListItem {\n id: string\n from: string\n to: string[]\n subject: string\n status: EmailStatus\n /** Always the object form, `{}` when the send carried no tags. */\n tags: Record<string, string>\n testMode: boolean\n createdAt: string\n}\n\nexport interface ListEmailsOptions {\n limit?: number\n cursor?: string\n status?: EmailStatus\n from?: string\n to?: string\n /**\n * Filter by tag. `'category:password_reset'` matches that exact pair; a bare\n * `'category'` matches any email carrying the tag. Pass an array to require several.\n */\n tag?: string | string[]\n}\n\nexport interface ListEmailsResponse {\n data: EmailListItem[]\n nextCursor: string | null\n}\n\nasync function resolveHtml(options: SendEmailOptions): Promise<string | undefined> {\n if (options.html) return options.html\n if (options.react) return renderReactEmail(options.react)\n return undefined\n}\n\nfunction encodeAttachmentContent(content: string | Uint8Array): string {\n // A string is assumed to already be base64. Raw bytes are encoded here.\n if (typeof content === 'string') return content\n if (typeof Buffer !== 'undefined') return Buffer.from(content).toString('base64')\n let binary = ''\n for (const byte of content) binary += String.fromCharCode(byte)\n return btoa(binary)\n}\n\nfunction toIsoString(value: string | Date): string {\n return value instanceof Date ? value.toISOString() : value\n}\n\nexport async function toApiPayload(options: SendEmailOptions) {\n const html = await resolveHtml(options)\n return {\n from: options.from,\n to: options.to,\n cc: options.cc,\n bcc: options.bcc,\n reply_to: options.replyTo,\n subject: options.subject,\n html,\n text: options.text,\n template_id: options.templateId,\n variables: options.variables,\n headers: options.headers,\n tags: options.tags,\n track_opens: options.trackOpens,\n track_clicks: options.trackClicks,\n attachments: options.attachments?.map((a) => ({\n filename: a.filename,\n content: a.content === undefined ? undefined : encodeAttachmentContent(a.content),\n path: a.path,\n content_type: a.contentType,\n content_id: a.contentId,\n })),\n scheduled_at: options.scheduledAt ? toIsoString(options.scheduledAt) : undefined,\n }\n}\n\nexport class Emails {\n constructor(private readonly client: Eusend) {}\n\n async send(\n options: SendEmailOptions,\n requestOptions?: SendEmailRequestOptions,\n ): Promise<EusendResponse<SendEmailResponse>> {\n const extraHeaders: Record<string, string> = {}\n if (requestOptions?.idempotencyKey) {\n extraHeaders['Idempotency-Key'] = requestOptions.idempotencyKey\n }\n const payload = await toApiPayload(options)\n return this.client.post<SendEmailResponse>('/emails', payload, extraHeaders)\n }\n\n async list(options: ListEmailsOptions = {}): Promise<EusendResponse<ListEmailsResponse>> {\n const params = new URLSearchParams()\n if (options.limit != null) params.set('limit', String(options.limit))\n if (options.cursor) params.set('cursor', options.cursor)\n if (options.status) params.set('status', options.status)\n if (options.from) params.set('from', options.from)\n if (options.to) params.set('to', options.to)\n // Repeated `tag` params, one per filter — the API ANDs them.\n for (const tag of options.tag == null ? [] : [options.tag].flat()) {\n params.append('tag', tag)\n }\n const qs = params.toString()\n\n const res = await this.client.get<{ data: EmailListItem[]; next_cursor: string | null }>(\n qs ? `/emails?${qs}` : '/emails',\n )\n if (res.error) return res\n return {\n data: { data: res.data.data, nextCursor: res.data.next_cursor },\n error: null,\n headers: res.headers,\n }\n }\n\n get(id: string): Promise<EusendResponse<Email>> {\n return this.client.get<Email>(`/emails/${id}`)\n }\n\n /**\n * Reschedule a scheduled email. Fails once the email has started sending, and returns\n * 429 `DAILY_LIMIT_EXCEEDED` when the new day's sending quota is already used up.\n */\n async update(\n id: string,\n options: UpdateEmailOptions,\n ): Promise<EusendResponse<UpdateEmailResponse>> {\n const res = await this.client.patch<{ id: string; status: 'scheduled'; scheduled_at: string }>(\n `/emails/${id}`,\n { scheduled_at: toIsoString(options.scheduledAt) },\n )\n if (res.error) return res\n return {\n data: { id: res.data.id, status: res.data.status, scheduledAt: res.data.scheduled_at },\n error: null,\n headers: res.headers,\n }\n }\n\n /** Cancel a scheduled email. Fails once the email has started sending. */\n cancel(id: string): Promise<EusendResponse<CancelEmailResponse>> {\n return this.client.post<CancelEmailResponse>(`/emails/${id}/cancel`, undefined)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\nimport {\n toApiPayload,\n type SendEmailOptions,\n type SendEmailRequestOptions,\n type BatchSendResponse,\n} from './emails'\n\n/**\n * Batch sending — `eusend.batch.send([...])`. The method path mirrors Resend's\n * `resend.batch.send([...])`, so migrating is a mechanical `resend` → `eusend` rename.\n * The HTTP body is a top-level array of email objects (POST /emails/batch), up to 100\n * per request. As with Resend, attachments and `scheduledAt` are not supported on the\n * batch endpoint — send those individually via `emails.send`.\n *\n * The response maps positionally to the input: `data[i]` is `{ id }` when\n * `emails[i]` was queued, or `{ error, code }` when it was not (unverified\n * domain, suppressed recipients, exhausted quota, …) — failed items never fail\n * the whole batch, so branch on the presence of `id` per item.\n *\n * Pass `{ idempotencyKey }` to retry safely: the key is applied per item by position, so\n * a retry must keep the items in the same order or it will match the wrong emails.\n */\nexport class Batch {\n constructor(private readonly client: Eusend) {}\n\n async send(\n emails: SendEmailOptions[],\n requestOptions?: SendEmailRequestOptions,\n ): Promise<EusendResponse<BatchSendResponse>> {\n const extraHeaders: Record<string, string> = {}\n if (requestOptions?.idempotencyKey) {\n extraHeaders['Idempotency-Key'] = requestOptions.idempotencyKey\n }\n const payloads = await Promise.all(emails.map(toApiPayload))\n return this.client.post<BatchSendResponse>('/emails/batch', payloads, extraHeaders)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\nexport type DomainStatus = 'pending' | 'verified' | 'failed'\n\nexport interface DnsRecord {\n type: string\n name: string\n value: string\n /** MX records only. */\n priority?: number\n /**\n * `authentication` — required before the domain can send.\n * `policy` — recommended; absence weakens but does not block.\n * `alignment` — optional; publishing all of them enables Return-Path SPF alignment.\n */\n purpose?: string\n description?: string\n}\n\nexport interface CreateDomainResponse {\n id: string\n name: string\n /**\n * Every record to publish, in presentation order. Prefer this over the individual\n * keys below — it is the only place the optional Return-Path alignment records appear.\n */\n records: DnsRecord[]\n dkim: DnsRecord\n dmarc: DnsRecord\n}\n\nexport interface DomainListItem {\n id: string\n name: string\n status: DomainStatus\n createdAt: string\n}\n\n/** Whether a verification chain is polling DNS for this domain right now. */\nexport interface DomainVerification {\n running: boolean\n /** When the running chain started, or null when none is. */\n startedAt: string | null\n}\n\n/**\n * What the last unmatched DNS check found, when it found a mistake rather than an absence.\n *\n * `code` is the mistake: `doubled_domain` (the record sits under the domain twice, because the\n * control panel appends it to whatever you type), `truncated_key` (the value was cut at the\n * 255-character limit for a single DNS string instead of being split into two), `foreign_key`\n * (a DKIM key we did not issue is published at the selector), `quoted_value`, `multiple_records`,\n * `cname_at_selector`. New codes may be added, so treat an unknown one as generic.\n */\nexport interface DomainDiagnostic {\n code: string\n /** The name the record was actually found at, for `doubled_domain`. */\n foundAt?: string\n /** How much of the key is published, and how much there is, for `truncated_key`. */\n publishedChars?: number\n expectedChars?: number\n /** Where the CNAME points, for `cname_at_selector`. */\n target?: string\n /** The DNS host serving the zone, when its nameservers named one we recognise. */\n provider?: {\n id: string\n label: string\n /** Path to the guide for this panel on eusend.dev, or null where there is none. */\n guide: string | null\n }\n}\n\nexport interface Domain {\n id: string\n name: string\n dkimPublicKey: string\n dkimSelector: string\n status: DomainStatus\n createdAt: string\n verifiedAt: string | null\n verification: DomainVerification\n /** Null while nothing is wrong beyond the records not having propagated yet. */\n diagnostic: DomainDiagnostic | null\n}\n\nexport interface DeleteDomainResponse {\n message: string\n /** Scheduled emails from this domain that were canceled because it can no longer send. */\n canceled_scheduled_emails: number\n}\n\nexport class Domains {\n constructor(private readonly client: Eusend) {}\n\n create(name: string): Promise<EusendResponse<CreateDomainResponse>> {\n return this.client.post<CreateDomainResponse>('/domains', { name })\n }\n\n list(): Promise<EusendResponse<DomainListItem[]>> {\n return this.client.get<DomainListItem[]>('/domains')\n }\n\n get(id: string): Promise<EusendResponse<Domain>> {\n return this.client.get<Domain>(`/domains/${id}`)\n }\n\n delete(id: string): Promise<EusendResponse<DeleteDomainResponse>> {\n return this.client.delete<DeleteDomainResponse>(`/domains/${id}`)\n }\n\n verify(id: string): Promise<EusendResponse<{ message: string }>> {\n return this.client.post<{ message: string }>(`/domains/${id}/verify`)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\n/**\n * What a key may reach. `full_access` is every resource; `sending_access` is limited to\n * sending email (and rescheduling or canceling a scheduled send).\n */\nexport type ApiKeyPermission = 'full_access' | 'sending_access'\n\nexport interface CreateApiKeyOptions {\n name: string\n testMode?: boolean\n /** Defaults to `full_access`. */\n permission?: ApiKeyPermission\n /**\n * Restrict the key to sending from a single domain. Only valid together with\n * `permission: 'sending_access'`; omit for any verified domain.\n */\n domainId?: string\n}\n\nexport interface CreateApiKeyResponse {\n id: string\n name: string\n key: string\n prefix: string\n testMode: boolean\n permission: ApiKeyPermission\n domainId: string | null\n domainName: string | null\n createdAt: string\n}\n\nexport interface ApiKey {\n id: string\n name: string\n prefix: string\n testMode: boolean\n permission: ApiKeyPermission\n domainId: string | null\n domainName: string | null\n createdAt: string\n lastUsedAt: string | null\n}\n\ntype CreateApiKeyApiResponse = {\n id: string\n name: string\n key: string\n prefix: string\n test_mode: boolean\n permission: ApiKeyPermission\n domain_id: string | null\n domain_name: string | null\n created_at: string\n}\n\nexport class ApiKeys {\n constructor(private readonly client: Eusend) {}\n\n async create(options: CreateApiKeyOptions): Promise<EusendResponse<CreateApiKeyResponse>> {\n const res = await this.client.post<CreateApiKeyApiResponse>('/api-keys', {\n name: options.name,\n test_mode: options.testMode ?? false,\n permission: options.permission ?? 'full_access',\n ...(options.domainId ? { domain_id: options.domainId } : {}),\n })\n if (res.error) return res\n return {\n data: {\n id: res.data.id,\n name: res.data.name,\n key: res.data.key,\n prefix: res.data.prefix,\n testMode: res.data.test_mode,\n permission: res.data.permission,\n domainId: res.data.domain_id,\n domainName: res.data.domain_name,\n createdAt: res.data.created_at,\n },\n error: null,\n headers: res.headers,\n }\n }\n\n list(): Promise<EusendResponse<ApiKey[]>> {\n return this.client.get<ApiKey[]>('/api-keys')\n }\n\n delete(id: string): Promise<EusendResponse<{ message: string }>> {\n return this.client.delete<{ message: string }>(`/api-keys/${id}`)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\nexport type ContactStatus = 'subscribed' | 'unsubscribed'\n\nexport interface Audience {\n id: string\n name: string\n organizationId: string\n createdAt: string\n updatedAt: string\n}\n\nexport interface AudienceListItem {\n id: string\n name: string\n createdAt: string\n contactCount: number\n}\n\nexport interface AudienceDetail extends AudienceListItem {\n updatedAt: string\n}\n\nexport interface UpdateAudienceOptions {\n name: string\n}\n\nexport interface Contact {\n id: string\n audienceId: string\n email: string\n firstName: string | null\n lastName: string | null\n /** Custom properties, available as `{{key}}` in a broadcast body. */\n properties: Record<string, string>\n status: ContactStatus\n unsubscribedAt: string | null\n createdAt: string\n updatedAt: string\n}\n\nexport interface CreateContactOptions {\n email: string\n firstName?: string\n lastName?: string\n /**\n * Custom properties, merged into the `{{variable}}` map when a broadcast renders, so\n * `{ plan: 'pro' }` makes `{{plan}}` resolve to `pro`.\n *\n * Values are strings; keys are lowercase letters, digits and underscores, starting with\n * a letter (at most 40 characters, 20 properties per contact). `email`, `name`,\n * `first_name`, `last_name` and `full_name` are built in and cannot be used.\n *\n * Sending this REPLACES the contact's properties. Omitting it on `createContact` clears\n * them; omitting it on `updateContact` leaves them untouched.\n */\n properties?: Record<string, string>\n}\n\nexport interface UpdateContactOptions {\n firstName?: string\n lastName?: string\n unsubscribed?: boolean\n /** Replaces the contact's custom properties. Omit to leave them unchanged; pass `{}` to\n * clear them. See {@link CreateContactOptions.properties} for the naming rules. */\n properties?: Record<string, string>\n}\n\nexport interface ListContactsOptions {\n limit?: number\n cursor?: string\n search?: string\n subscribed?: boolean\n}\n\nexport interface ListContactsResponse {\n data: Contact[]\n nextCursor: string | null\n}\n\n/**\n * A contact in a bulk import. Extends the single-create shape with the two fields that\n * only make sense when migrating a list in from somewhere else.\n */\nexport interface BatchContactOptions extends CreateContactOptions {\n /**\n * Mark the contact as opted out, so a list moved from another provider keeps its\n * unsubscribes. An import can only ever ADD an opt-out: passing `false` will not\n * re-subscribe someone who has already unsubscribed. Use `updateContact` for that,\n * one contact at a time.\n */\n unsubscribed?: boolean\n /** Original signup time (ISO 8601). Applied on insert only — an existing contact\n * keeps the date it already has. */\n createdAt?: string\n /**\n * Unlike `createContact`, an import MERGES properties into whatever the contact already\n * has — a CSV carrying only `plan` will not drop a `company` an earlier import set. To\n * replace the whole object, use `updateContact`.\n */\n properties?: Record<string, string>\n}\n\nexport interface BatchCreateContactsOptions {\n contacts: BatchContactOptions[]\n}\n\nexport class Audiences {\n constructor(private readonly client: Eusend) {}\n\n create(name: string): Promise<EusendResponse<Audience>> {\n return this.client.post<Audience>('/audiences', { name })\n }\n\n async list(): Promise<EusendResponse<AudienceListItem[]>> {\n const res = await this.client.get<{ data: AudienceListItem[] }>('/audiences')\n if (res.error) return res\n return { data: res.data.data, error: null, headers: res.headers }\n }\n\n get(id: string): Promise<EusendResponse<AudienceDetail>> {\n return this.client.get<AudienceDetail>(`/audiences/${id}`)\n }\n\n /** Rename an audience. */\n update(id: string, options: UpdateAudienceOptions): Promise<EusendResponse<Audience>> {\n return this.client.patch<Audience>(`/audiences/${id}`, { name: options.name })\n }\n\n delete(id: string): Promise<EusendResponse<Record<string, never>>> {\n return this.client.delete<Record<string, never>>(`/audiences/${id}`)\n }\n\n createContact(\n audienceId: string,\n options: CreateContactOptions,\n ): Promise<EusendResponse<Contact>> {\n return this.client.post<Contact>(`/audiences/${audienceId}/contacts`, {\n email: options.email,\n first_name: options.firstName,\n last_name: options.lastName,\n properties: options.properties,\n })\n }\n\n async listContacts(\n audienceId: string,\n options: ListContactsOptions = {},\n ): Promise<EusendResponse<ListContactsResponse>> {\n const params = new URLSearchParams()\n if (options.limit != null) params.set('limit', String(options.limit))\n if (options.cursor) params.set('cursor', options.cursor)\n if (options.search) params.set('search', options.search)\n if (options.subscribed != null) params.set('subscribed', String(options.subscribed))\n const qs = params.toString()\n return this.client.get<ListContactsResponse>(\n qs ? `/audiences/${audienceId}/contacts?${qs}` : `/audiences/${audienceId}/contacts`,\n )\n }\n\n getContact(audienceId: string, contactId: string): Promise<EusendResponse<Contact>> {\n return this.client.get<Contact>(`/audiences/${audienceId}/contacts/${contactId}`)\n }\n\n updateContact(\n audienceId: string,\n contactId: string,\n options: UpdateContactOptions,\n ): Promise<EusendResponse<Contact>> {\n return this.client.patch<Contact>(`/audiences/${audienceId}/contacts/${contactId}`, {\n first_name: options.firstName,\n last_name: options.lastName,\n unsubscribed: options.unsubscribed,\n properties: options.properties,\n })\n }\n\n deleteContact(\n audienceId: string,\n contactId: string,\n ): Promise<EusendResponse<Record<string, never>>> {\n return this.client.delete<Record<string, never>>(\n `/audiences/${audienceId}/contacts/${contactId}`,\n )\n }\n\n /**\n * Upsert up to 1000 contacts in one call. Addresses are lowercased and\n * de-duplicated server-side; `count` is the number of rows written and\n * `duplicates` how many repeated addresses were collapsed to get there.\n */\n /**\n * Delete up to 1,000 contacts from an audience by id.\n *\n * `deleted` may be lower than the number of ids sent — an id may already be gone, or\n * may belong to another audience — so a retry after a dropped response settles at 0\n * rather than failing.\n *\n * This is not an unsubscribe. It removes them from the audience without adding them to\n * the suppression list; use `updateContact({ unsubscribed: true })` to stop mailing\n * somebody while keeping the record.\n */\n batchDeleteContacts(\n audienceId: string,\n contactIds: string[],\n ): Promise<EusendResponse<{ deleted: number }>> {\n return this.client.post<{ deleted: number }>(\n `/audiences/${audienceId}/contacts/batch-delete`,\n { contact_ids: contactIds },\n )\n }\n\n batchCreateContacts(\n audienceId: string,\n options: BatchCreateContactsOptions,\n ): Promise<EusendResponse<{ count: number; duplicates: number }>> {\n return this.client.post<{ count: number; duplicates: number }>(\n `/audiences/${audienceId}/contacts/batch`,\n {\n contacts: options.contacts.map((c) => ({\n email: c.email,\n first_name: c.firstName,\n last_name: c.lastName,\n unsubscribed: c.unsubscribed,\n created_at: c.createdAt,\n properties: c.properties,\n })),\n },\n )\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\n/**\n * A declared property's type. Values are carried and rendered as strings either way —\n * `number` buys a write-time check, not arithmetic or locale formatting.\n */\nexport type ContactPropertyType = 'string' | 'number'\n\nexport interface ContactProperty {\n id: string\n key: string\n type: ContactPropertyType\n /** Substituted into `{{key}}` for contacts that carry no value of their own. `null`\n * renders empty, which is what an unset property did before the registry existed. */\n fallbackValue: string | null\n createdAt: string\n updatedAt: string\n}\n\nexport interface CreateContactPropertyOptions {\n /** Lowercase letters, digits and underscores, starting with a letter; at most 40\n * characters. `email`, `name`, `first_name`, `last_name` and `full_name` are built in\n * and cannot be declared. */\n key: string\n /** Defaults to `string`. */\n type?: ContactPropertyType\n fallbackValue?: string | null\n}\n\nexport interface UpdateContactPropertyOptions {\n /** The only mutable field. `key` and `type` are fixed at creation: a rename would have\n * to rewrite every contact and every broadcast body spelling `{{old_key}}`, so changing\n * either is a delete and a create. */\n fallbackValue: string | null\n}\n\nexport interface DeleteContactPropertyResponse {\n deleted: true\n /** How many contacts had the key stripped from them. */\n contactsUpdated: number\n}\n\n/**\n * The organization's custom contact properties — the schema behind the `properties` bag\n * each contact carries.\n *\n * Declaring a property is optional. A property arriving on a contact write that has never\n * been declared registers itself as a `string`, so an existing integration needs no\n * changes. Declaring one up front is what buys a type check and a fallback value.\n */\nexport class ContactProperties {\n constructor(private readonly client: Eusend) {}\n\n create(options: CreateContactPropertyOptions): Promise<EusendResponse<ContactProperty>> {\n return this.client.post<ContactProperty>('/contact-properties', {\n key: options.key,\n type: options.type,\n fallback_value: options.fallbackValue,\n })\n }\n\n /** Every property the organization has defined. Unpaginated — the registry is capped at\n * 100 entries, and a variable picker wants all of them. */\n async list(): Promise<EusendResponse<ContactProperty[]>> {\n const res = await this.client.get<{ data: ContactProperty[] }>('/contact-properties')\n if (res.error) return res\n return { data: res.data.data, error: null, headers: res.headers }\n }\n\n get(id: string): Promise<EusendResponse<ContactProperty>> {\n return this.client.get<ContactProperty>(`/contact-properties/${id}`)\n }\n\n update(\n id: string,\n options: UpdateContactPropertyOptions,\n ): Promise<EusendResponse<ContactProperty>> {\n return this.client.patch<ContactProperty>(`/contact-properties/${id}`, {\n fallback_value: options.fallbackValue,\n })\n }\n\n /**\n * Delete a property definition AND strip the key from every contact in the organization.\n *\n * Destructive and not undoable. Leaving the values in place was the alternative, and a\n * worse one: the property would keep rendering in broadcasts, and the next contact write\n * carrying that key would register it again.\n */\n delete(id: string): Promise<EusendResponse<DeleteContactPropertyResponse>> {\n return this.client.delete<DeleteContactPropertyResponse>(`/contact-properties/${id}`)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\n/** What a contact who has never expressed a preference receives. Fixed at creation. */\nexport type TopicDefaultSubscription = 'opt_in' | 'opt_out'\n\n/** Whether the topic is listed on the unsubscribe page to a contact who is not opted in. */\nexport type TopicVisibility = 'public' | 'private'\n\nexport interface Topic {\n id: string\n name: string\n description: string | null\n defaultSubscription: TopicDefaultSubscription\n visibility: TopicVisibility\n /** Contacts who explicitly opted in. Present on list and create, not on get. */\n subscriberCount?: number\n createdAt: string\n updatedAt: string\n}\n\nexport interface CreateTopicOptions {\n name: string\n /** `opt_in` reaches everyone until they leave; `opt_out` reaches nobody until they join.\n * Cannot be changed afterwards. */\n defaultSubscription: TopicDefaultSubscription\n description?: string | null\n /** Defaults to `private`. */\n visibility?: TopicVisibility\n}\n\n/** `defaultSubscription` is absent deliberately — it is fixed at creation. */\nexport interface UpdateTopicOptions {\n name?: string\n description?: string | null\n visibility?: TopicVisibility\n}\n\nexport interface DeleteTopicResponse {\n id: string\n deleted: true\n}\n\nexport interface TopicSubscriptionResponse {\n topicId: string\n contactId: string\n subscribed: boolean\n}\n\nexport interface ClearTopicSubscriptionResponse {\n topicId: string\n contactId: string\n deleted: true\n}\n\nexport class Topics {\n constructor(private readonly client: Eusend) {}\n\n create(options: CreateTopicOptions): Promise<EusendResponse<Topic>> {\n return this.client.post<Topic>('/topics', {\n name: options.name,\n default_subscription: options.defaultSubscription,\n description: options.description,\n visibility: options.visibility,\n })\n }\n\n /** Every topic the organization has defined. Unpaginated — the list is capped at 100,\n * and both the composer's picker and the unsubscribe page want all of it. */\n async list(): Promise<EusendResponse<Topic[]>> {\n const res = await this.client.get<{ data: Topic[] }>('/topics')\n if (res.error) return res\n return { data: res.data.data, error: null, headers: res.headers }\n }\n\n get(id: string): Promise<EusendResponse<Topic>> {\n return this.client.get<Topic>(`/topics/${id}`)\n }\n\n update(id: string, options: UpdateTopicOptions): Promise<EusendResponse<Topic>> {\n return this.client.patch<Topic>(`/topics/${id}`, {\n name: options.name,\n description: options.description,\n visibility: options.visibility,\n })\n }\n\n /** Deletes the topic and every stored preference for it. A draft broadcast scoped to it\n * widens back to its whole audience; returns 409 while a broadcast that is scheduled or\n * has not finished sending still uses the topic. */\n delete(id: string): Promise<EusendResponse<DeleteTopicResponse>> {\n return this.client.delete<DeleteTopicResponse>(`/topics/${id}`)\n }\n\n /** Record an explicit preference for one contact. */\n subscribe(\n topicId: string,\n contactId: string,\n subscribed = true,\n ): Promise<EusendResponse<TopicSubscriptionResponse>> {\n return this.client.put<TopicSubscriptionResponse>(\n `/topics/${topicId}/contacts/${contactId}`,\n { subscribed },\n )\n }\n\n /**\n * Forget the contact's explicit choice, so they fall back to the topic's default.\n *\n * Different from `subscribe(id, contactId, false)`: that records \"no thanks\", this\n * records nothing at all — so on an opt-in topic the contact starts receiving it again.\n */\n clearSubscription(\n topicId: string,\n contactId: string,\n ): Promise<EusendResponse<ClearTopicSubscriptionResponse>> {\n return this.client.delete<ClearTopicSubscriptionResponse>(\n `/topics/${topicId}/contacts/${contactId}`,\n )\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\nimport { renderReactEmail, type ReactEmailElement } from './react-render'\n\ninterface TemplateHtmlOrReact {\n /**\n * A React Email component. The SDK renders it to HTML locally before sending.\n * Requires `@react-email/render` and `react` as peer dependencies.\n * Ignored when `html` is also provided.\n */\n react?: ReactEmailElement\n}\n\nexport interface CreateTemplateOptions extends TemplateHtmlOrReact {\n name: string\n subject: string\n html?: string\n}\n\nexport interface UpdateTemplateOptions extends TemplateHtmlOrReact {\n name?: string\n subject?: string\n html?: string\n}\n\nexport interface Template {\n id: string\n name: string\n subject: string\n html: string | null\n reactSource: string | null\n createdAt: string\n updatedAt: string\n}\n\nexport interface TemplateListItem {\n id: string\n name: string\n subject: string\n createdAt: string\n updatedAt: string\n}\n\nasync function resolveTemplateHtml(\n options: TemplateHtmlOrReact & { html?: string },\n): Promise<string | undefined> {\n if (options.html) return options.html\n if (options.react) return renderReactEmail(options.react)\n return undefined\n}\n\nexport class Templates {\n constructor(private readonly client: Eusend) {}\n\n async create(options: CreateTemplateOptions): Promise<EusendResponse<Template>> {\n const html = await resolveTemplateHtml(options)\n if (!html) {\n return {\n data: null,\n error: {\n message: 'Either html or react is required',\n statusCode: null,\n name: 'VALIDATION_ERROR',\n },\n headers: null,\n }\n }\n return this.client.post<Template>('/templates', {\n name: options.name,\n subject: options.subject,\n html,\n })\n }\n\n async list(): Promise<EusendResponse<TemplateListItem[]>> {\n const res = await this.client.get<{ data: TemplateListItem[] }>('/templates')\n if (res.error) return res\n return { data: res.data.data, error: null, headers: res.headers }\n }\n\n get(id: string): Promise<EusendResponse<Template>> {\n return this.client.get<Template>(`/templates/${id}`)\n }\n\n async update(id: string, options: UpdateTemplateOptions): Promise<EusendResponse<Template>> {\n const html = await resolveTemplateHtml(options)\n return this.client.patch<Template>(`/templates/${id}`, {\n name: options.name,\n subject: options.subject,\n html,\n })\n }\n\n delete(id: string): Promise<EusendResponse<Record<string, never>>> {\n return this.client.delete<Record<string, never>>(`/templates/${id}`)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\nexport type WebhookEvent =\n | 'email.sent'\n | 'email.delivered'\n | 'email.bounced'\n | 'email.complained'\n | 'email.opened'\n | 'email.clicked'\n | 'email.failed'\n | 'email.suppressed'\n | '*'\n\nexport interface CreateWebhookOptions {\n url: string\n events: WebhookEvent[]\n}\n\nexport interface UpdateWebhookOptions {\n url?: string\n events?: WebhookEvent[]\n}\n\nexport interface WebhookDelivery {\n id: string\n webhookId: string\n emailId: string | null\n eventType: string\n payload: Record<string, unknown>\n status: 'pending' | 'success' | 'failed'\n responseStatus: number | null\n attempts: number\n createdAt: string\n lastAttemptAt: string | null\n}\n\nexport interface Webhook {\n id: string\n url: string\n events: WebhookEvent[]\n createdAt: string\n}\n\nexport interface WebhookWithDeliveries extends Webhook {\n deliveries: WebhookDelivery[]\n}\n\nexport interface CreateWebhookResponse extends Webhook {\n secret: string\n}\n\nexport class Webhooks {\n constructor(private readonly client: Eusend) {}\n\n create(options: CreateWebhookOptions): Promise<EusendResponse<CreateWebhookResponse>> {\n return this.client.post<CreateWebhookResponse>('/webhooks', {\n url: options.url,\n events: options.events,\n })\n }\n\n async list(): Promise<EusendResponse<Webhook[]>> {\n const res = await this.client.get<{ data: Webhook[] }>('/webhooks')\n if (res.error) return res\n return { data: res.data.data, error: null, headers: res.headers }\n }\n\n get(id: string): Promise<EusendResponse<WebhookWithDeliveries>> {\n return this.client.get<WebhookWithDeliveries>(`/webhooks/${id}`)\n }\n\n update(id: string, options: UpdateWebhookOptions): Promise<EusendResponse<Webhook>> {\n return this.client.patch<Webhook>(`/webhooks/${id}`, {\n url: options.url,\n events: options.events,\n })\n }\n\n delete(id: string): Promise<EusendResponse<Record<string, never>>> {\n return this.client.delete<Record<string, never>>(`/webhooks/${id}`)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\nimport { renderReactEmail, type ReactEmailElement } from './react-render'\n\n/**\n * `held` is a list send stopped part-way pending review. Unlike `paused` it cannot be\n * resumed by sending again — `send()` returns BROADCAST_HELD until the review clears.\n */\nexport type BroadcastStatus =\n 'draft' | 'scheduled' | 'sending' | 'sent' | 'paused' | 'held' | 'cancelled'\n\nexport interface CreateBroadcastOptions {\n name: string\n audienceId: string\n /** Narrows the audience to the contacts subscribed to this topic. Omit to send to all\n * of it. */\n topicId?: string\n /**\n * Sender address. Accepts a bare email (`onboarding@eusend.dev`) or a display-name\n * form (`Acme <onboarding@eusend.dev>`). The domain must be verified on your account.\n */\n from: string\n /** Where replies go. Same formats as `from`; omit to have replies go to the sender. */\n replyTo?: string\n subject: string\n html?: string\n /**\n * A React Email component. The SDK renders it to HTML locally before sending —\n * the JSX source never travels over the wire. Requires `@react-email/render`\n * and `react` as peer dependencies. Ignored when `html` is also provided.\n */\n react?: ReactEmailElement\n templateId?: string\n templateVariables?: Record<string, string>\n /**\n * Embed the open-tracking pixel for this broadcast. Omit to use your organization's\n * default (Settings → General → Email tracking); `false` always wins over it.\n */\n trackOpens?: boolean\n /**\n * Rewrite links so clicks are recorded. Omit to use your organization's default;\n * `false` leaves the original URLs untouched in the delivered mail.\n */\n trackClicks?: boolean\n}\n\nexport interface UpdateBroadcastOptions {\n name?: string\n audienceId?: string\n /** Pass null to clear the topic and widen the send back to the whole audience. */\n topicId?: string | null\n from?: string\n /** Pass null to clear it, so replies go back to the sender. */\n replyTo?: string | null\n subject?: string\n html?: string\n /**\n * See `react` on CreateBroadcastOptions. Rendered to HTML locally before sending.\n */\n react?: ReactEmailElement\n templateId?: string | null\n templateVariables?: Record<string, string> | null\n scheduledAt?: string | null\n /**\n * Embed the open-tracking pixel for this broadcast. Omit to use your organization's\n * default (Settings → General → Email tracking); `false` always wins over it.\n */\n trackOpens?: boolean\n /**\n * Rewrite links so clicks are recorded. Omit to use your organization's default;\n * `false` leaves the original URLs untouched in the delivered mail.\n */\n trackClicks?: boolean\n}\n\nexport interface SendBroadcastOptions {\n scheduledAt?: string\n}\n\nexport interface Broadcast {\n id: string\n organizationId: string\n name: string\n status: BroadcastStatus\n /** Null when the associated audience has been deleted. */\n audienceId: string | null\n /** The topic this broadcast is scoped to, or null for the whole audience. */\n topicId: string | null\n fromAddress: string\n replyTo: string | null\n subject: string\n html: string | null\n reactSource: string | null\n editorJson: Record<string, unknown> | null\n templateId: string | null\n templateVariables: Record<string, string> | null\n heldReason: string | null\n scheduledAt: string | null\n startedAt: string | null\n completedAt: string | null\n recipientCount: number | null\n sentCount: number | null\n trackOpens: boolean\n trackClicks: boolean\n createdAt: string\n updatedAt: string\n}\n\nexport interface BroadcastListItem {\n id: string\n name: string\n status: BroadcastStatus\n /** Null when the associated audience has been deleted. */\n audienceId: string | null\n topicId: string | null\n topicName: string | null\n fromAddress: string\n subject: string\n recipientCount: number | null\n sentCount: number | null\n scheduledAt: string | null\n startedAt: string | null\n completedAt: string | null\n createdAt: string\n audienceName: string | null\n}\n\nexport interface BroadcastDetail extends Broadcast {\n stats: Record<string, number>\n}\n\nexport interface TestBroadcastOptions {\n /**\n * Up to 5 addresses, each on a domain verified on your account. A test send delivers\n * real mail without the paid-plan gate that `send()` carries, so it is restricted to\n * inboxes you have already proved you control; anything else returns\n * `DOMAIN_NOT_VERIFIED`.\n */\n to: string[]\n}\n\nexport interface TestBroadcastResponse {\n id: string\n /** The addresses actually mailed, lowercased and de-duplicated. */\n sentTo: string[]\n /** One email id per recipient, for looking the delivery up in the logs. */\n emailIds: string[]\n}\n\nexport interface SendBroadcastResponse {\n id: string\n status: 'sending' | 'scheduled'\n scheduledAt: string | null\n}\n\nasync function resolveBroadcastHtml(options: {\n html?: string\n react?: ReactEmailElement\n}): Promise<string | undefined> {\n if (options.html) return options.html\n if (options.react) return renderReactEmail(options.react)\n return undefined\n}\n\nexport class Broadcasts {\n constructor(private readonly client: Eusend) {}\n\n async create(options: CreateBroadcastOptions): Promise<EusendResponse<Broadcast>> {\n const html = await resolveBroadcastHtml(options)\n return this.client.post<Broadcast>('/broadcasts', {\n name: options.name,\n audience_id: options.audienceId,\n topic_id: options.topicId,\n from: options.from,\n reply_to: options.replyTo,\n subject: options.subject,\n html,\n template_id: options.templateId,\n template_variables: options.templateVariables,\n track_opens: options.trackOpens,\n track_clicks: options.trackClicks,\n })\n }\n\n async list(): Promise<EusendResponse<BroadcastListItem[]>> {\n const res = await this.client.get<{ data: BroadcastListItem[] }>('/broadcasts')\n if (res.error) return res\n return { data: res.data.data, error: null, headers: res.headers }\n }\n\n get(id: string): Promise<EusendResponse<BroadcastDetail>> {\n return this.client.get<BroadcastDetail>(`/broadcasts/${id}`)\n }\n\n /**\n * An update that leaves the broadcast scheduled — setting `scheduledAt`, or editing one\n * that already is — runs the same checks as `send()` and can return the same 403s.\n * Unscheduling with `scheduledAt: null` is always allowed.\n */\n async update(id: string, options: UpdateBroadcastOptions): Promise<EusendResponse<Broadcast>> {\n const html = await resolveBroadcastHtml(options)\n return this.client.patch<Broadcast>(`/broadcasts/${id}`, {\n name: options.name,\n audience_id: options.audienceId,\n topic_id: options.topicId,\n from: options.from,\n reply_to: options.replyTo,\n subject: options.subject,\n html,\n template_id: options.templateId,\n template_variables: options.templateVariables,\n scheduled_at: options.scheduledAt,\n track_opens: options.trackOpens,\n track_clicks: options.trackClicks,\n })\n }\n\n async send(\n id: string,\n options: SendBroadcastOptions = {},\n ): Promise<EusendResponse<SendBroadcastResponse>> {\n // This endpoint is the one broadcast response that comes back snake_cased, so\n // map it rather than exposing a `scheduledAt` that is always undefined.\n const res = await this.client.post<{\n id: string\n status: 'sending' | 'scheduled'\n scheduled_at: string | null\n }>(`/broadcasts/${id}/send`, {\n scheduled_at: options.scheduledAt,\n })\n if (res.error) return res\n return {\n data: { id: res.data.id, status: res.data.status, scheduledAt: res.data.scheduled_at },\n error: null,\n headers: res.headers,\n }\n }\n\n /**\n * Send yourself a copy before the campaign goes out — the real message through the real\n * sending path, so it shows what a recipient will see.\n *\n * Works on every plan including Free, unlike `send()`. It costs daily and monthly quota\n * like any other send, and does NOT move the broadcast's status: the campaign stays a\n * draft no matter how many tests you send.\n *\n * Requires a LIVE api key. \"Test\" here means a dress rehearsal, not a sandbox — a\n * `eu_test_` key is refused because the mail really is delivered.\n */\n async test(\n id: string,\n options: TestBroadcastOptions,\n ): Promise<EusendResponse<TestBroadcastResponse>> {\n // Snake-cased on the wire, like the send() response above.\n const res = await this.client.post<{\n id: string\n sent_to: string[]\n email_ids: string[]\n }>(`/broadcasts/${id}/test`, { to: options.to })\n if (res.error) return res\n return {\n data: { id: res.data.id, sentTo: res.data.sent_to, emailIds: res.data.email_ids },\n error: null,\n headers: res.headers,\n }\n }\n\n cancel(id: string): Promise<EusendResponse<Broadcast>> {\n return this.client.post<Broadcast>(`/broadcasts/${id}/cancel`)\n }\n\n delete(id: string): Promise<EusendResponse<Record<string, never>>> {\n return this.client.delete<Record<string, never>>(`/broadcasts/${id}`)\n }\n}\n","import type { Eusend } from './eusend'\nimport type { EusendResponse } from './interfaces'\n\nexport type SuppressionReason = 'bounce' | 'complaint' | 'manual'\n\nexport interface SuppressionEntry {\n id: string\n email: string\n reason: SuppressionReason\n created_at: string\n}\n\nexport interface ListSuppressionsOptions {\n /** Filter to addresses containing this substring. Pass a domain (\"@acme.com\") to see every suppressed address there. */\n email?: string\n reason?: SuppressionReason\n limit?: number\n cursor?: string\n}\n\nexport interface ListSuppressionsResponse {\n data: SuppressionEntry[]\n next_cursor: string | null\n}\n\nexport interface CreateSuppressionOptions {\n email: string\n /** Defaults to 'manual'. An add never overwrites the reason an address is already suppressed for. */\n reason?: SuppressionReason\n}\n\n/** An item in an import — a bare address, or an address with the reason it was suppressed. */\nexport type SuppressionImportItem = string | { email: string; reason?: SuppressionReason }\n\nexport interface ImportSuppressionsResponse {\n /** Entries written. */\n count: number\n /** Entries that were already on the list. */\n already_suppressed: number\n /** Repeated addresses in the payload, collapsed before the write. */\n duplicates: number\n}\n\n/**\n * The addresses your organization will not send to.\n *\n * Hard bounces and spam complaints are added automatically; these methods cover the\n * addresses you manage yourself. Suppression applies to live sending only — test-mode\n * keys can read the list but not modify it.\n */\nexport class Suppressions {\n constructor(private readonly client: Eusend) {}\n\n list(options: ListSuppressionsOptions = {}): Promise<EusendResponse<ListSuppressionsResponse>> {\n const params = new URLSearchParams()\n if (options.email) params.set('email', options.email)\n if (options.reason) params.set('reason', options.reason)\n if (options.limit != null) params.set('limit', String(options.limit))\n if (options.cursor) params.set('cursor', options.cursor)\n const qs = params.toString()\n return this.client.get<ListSuppressionsResponse>(qs ? `/suppressions?${qs}` : '/suppressions')\n }\n\n /**\n * Suppress an address. If it is already suppressed the existing entry is returned\n * unchanged — a manual add never rewrites a real bounce or complaint.\n */\n create(options: CreateSuppressionOptions): Promise<EusendResponse<SuppressionEntry>> {\n return this.client.post<SuppressionEntry>('/suppressions', {\n email: options.email,\n reason: options.reason,\n })\n }\n\n /**\n * Import up to 1000 addresses in one call — for carrying a suppression list over from\n * another provider before your first send. Items may be bare addresses or objects.\n */\n import(emails: SuppressionImportItem[]): Promise<EusendResponse<ImportSuppressionsResponse>> {\n return this.client.post<ImportSuppressionsResponse>('/suppressions/batch', { emails })\n }\n\n /**\n * Un-suppress by entry id or by address, making the address sendable again.\n *\n * Removing an address that hard-bounced or complained is what damages a sender's\n * reputation when done in bulk — remove an entry when the address was fixed or the\n * complaint was a mistake, not to retry a failing list.\n */\n remove(idOrEmail: string): Promise<EusendResponse<{ deleted: number }>> {\n return this.client.delete<{ deleted: number }>(`/suppressions/${encodeURIComponent(idOrEmail)}`)\n }\n\n /** The whole list as CSV (`email,reason,created_at`), for backup or migration. */\n export(): Promise<EusendResponse<string>> {\n return this.client.fetchRequest<string>('/suppressions/export', { method: 'GET' }, {}, 'text')\n }\n}\n","import type { EusendError, EusendResponse } from './interfaces'\nimport { Emails } from './emails'\nimport { Batch } from './batch'\nimport { Domains } from './domains'\nimport { ApiKeys } from './api-keys'\nimport { Audiences } from './audiences'\nimport { ContactProperties } from './contact-properties'\nimport { Topics } from './topics'\nimport { Templates } from './templates'\nimport { Webhooks } from './webhooks'\nimport { Broadcasts } from './broadcasts'\nimport { Suppressions } from './suppressions'\n\nconst DEFAULT_BASE_URL = 'https://api.eusend.dev'\nconst SDK_VERSION = '0.19.0'\n\nexport interface EusendOptions {\n baseUrl?: string\n}\n\nexport class Eusend {\n readonly baseUrl: string\n private readonly apiKey: string\n\n readonly emails: Emails\n /** Batch sending — `client.batch.send([...])`. Mirrors Resend's `resend.batch.send()`. */\n readonly batch: Batch\n readonly domains: Domains\n readonly apiKeys: ApiKeys\n readonly audiences: Audiences\n /** The org's declared contact properties — `client.contactProperties.list()`. */\n readonly contactProperties: ContactProperties\n /** Subscription topics — `client.topics.list()`. */\n readonly topics: Topics\n readonly templates: Templates\n readonly webhooks: Webhooks\n readonly broadcasts: Broadcasts\n readonly suppressions: Suppressions\n\n constructor(key?: string, options?: EusendOptions) {\n const apiKey =\n key ?? (typeof process !== 'undefined' ? process.env['EUSEND_API_KEY'] : undefined)\n if (!apiKey) {\n throw new Error(\n 'Missing Eusend API key. Pass it to the constructor or set the EUSEND_API_KEY environment variable.',\n )\n }\n this.apiKey = apiKey\n this.baseUrl = options?.baseUrl ?? DEFAULT_BASE_URL\n\n this.emails = new Emails(this)\n this.batch = new Batch(this)\n this.domains = new Domains(this)\n this.apiKeys = new ApiKeys(this)\n this.audiences = new Audiences(this)\n this.contactProperties = new ContactProperties(this)\n this.topics = new Topics(this)\n this.templates = new Templates(this)\n this.webhooks = new Webhooks(this)\n this.broadcasts = new Broadcasts(this)\n this.suppressions = new Suppressions(this)\n }\n\n async fetchRequest<T>(\n path: string,\n init: RequestInit = {},\n extraHeaders: Record<string, string> = {},\n // Not every successful endpoint answers with JSON — the suppression export returns\n // CSV. Parsing that as JSON throws inside the try below, which would surface a\n // perfectly good download as \"Network request failed\".\n parse: 'json' | 'text' = 'json',\n ): Promise<EusendResponse<T>> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': `eusend-node/${SDK_VERSION}`,\n ...extraHeaders,\n }\n\n try {\n const res = await fetch(`${this.baseUrl}${path}`, { ...init, headers })\n const responseHeaders = Object.fromEntries(res.headers.entries())\n\n if (!res.ok) {\n let error: EusendError\n try {\n const json = (await res.json()) as { error?: string; code?: string }\n error = {\n message: json.error ?? 'Unknown error',\n statusCode: res.status,\n name: (json.code as EusendError['name']) ?? 'INTERNAL_ERROR',\n }\n } catch {\n error = { message: 'Request failed', statusCode: res.status, name: 'INTERNAL_ERROR' }\n }\n return { data: null, error, headers: responseHeaders }\n }\n\n if (res.status === 204 || res.headers.get('content-length') === '0') {\n return { data: {} as T, error: null, headers: responseHeaders }\n }\n\n const data = (parse === 'text' ? await res.text() : await res.json()) as T\n return { data, error: null, headers: responseHeaders }\n } catch {\n return {\n data: null,\n error: {\n message: 'Network request failed. The request could not be resolved.',\n statusCode: null,\n name: 'application_error',\n },\n headers: null,\n }\n }\n }\n\n get<T>(path: string, extraHeaders?: Record<string, string>): Promise<EusendResponse<T>> {\n return this.fetchRequest<T>(path, { method: 'GET' }, extraHeaders)\n }\n\n post<T>(\n path: string,\n body?: unknown,\n extraHeaders?: Record<string, string>,\n ): Promise<EusendResponse<T>> {\n return this.fetchRequest<T>(\n path,\n { method: 'POST', body: body != null ? JSON.stringify(body) : undefined },\n extraHeaders,\n )\n }\n\n patch<T>(path: string, body?: unknown): Promise<EusendResponse<T>> {\n return this.fetchRequest<T>(path, {\n method: 'PATCH',\n body: body != null ? JSON.stringify(body) : undefined,\n })\n }\n\n put<T>(path: string, body?: unknown): Promise<EusendResponse<T>> {\n return this.fetchRequest<T>(path, {\n method: 'PUT',\n body: body != null ? JSON.stringify(body) : undefined,\n })\n }\n\n delete<T>(path: string): Promise<EusendResponse<T>> {\n return this.fetchRequest<T>(path, { method: 'DELETE' })\n }\n}\n"],"mappings":";AASA,IAAI,gBAAiF;AAErF,eAAe,YAAsE;CACnF,IAAI,CAAC,eACH,iBAAiB,YAAY;EAC3B,IAAI;GACF,MAAM,MAAO,MAAM,OAAO;GAG1B,QAAQ,YAA+B,QAAQ,QAAQ,IAAI,OAAO,OAAO,CAAC;EAC5E,QAAQ;GACN,MAAM,IAAI,MACR,yHAEF;EACF;CACF,EAAA,CAAG;CAEL,OAAO;AACT;AAEA,eAAsB,iBAAiB,SAA6C;CAElF,QAAO,MADc,UAAU,EAAA,CACjB,OAAO;AACvB;;;ACuKA,eAAe,YAAY,SAAwD;CACjF,IAAI,QAAQ,MAAM,OAAO,QAAQ;CACjC,IAAI,QAAQ,OAAO,OAAO,iBAAiB,QAAQ,KAAK;AAE1D;AAEA,SAAS,wBAAwB,SAAsC;CAErE,IAAI,OAAO,YAAY,UAAU,OAAO;CACxC,IAAI,OAAO,WAAW,aAAa,OAAO,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,QAAQ;CAChF,IAAI,SAAS;CACb,KAAK,MAAM,QAAQ,SAAS,UAAU,OAAO,aAAa,IAAI;CAC9D,OAAO,KAAK,MAAM;AACpB;AAEA,SAAS,YAAY,OAA8B;CACjD,OAAO,iBAAiB,OAAO,MAAM,YAAY,IAAI;AACvD;AAEA,eAAsB,aAAa,SAA2B;CAC5D,MAAM,OAAO,MAAM,YAAY,OAAO;CACtC,OAAO;EACL,MAAM,QAAQ;EACd,IAAI,QAAQ;EACZ,IAAI,QAAQ;EACZ,KAAK,QAAQ;EACb,UAAU,QAAQ;EAClB,SAAS,QAAQ;EACjB;EACA,MAAM,QAAQ;EACd,aAAa,QAAQ;EACrB,WAAW,QAAQ;EACnB,SAAS,QAAQ;EACjB,MAAM,QAAQ;EACd,aAAa,QAAQ;EACrB,cAAc,QAAQ;EACtB,aAAa,QAAQ,aAAa,KAAK,OAAO;GAC5C,UAAU,EAAE;GACZ,SAAS,EAAE,YAAY,KAAA,IAAY,KAAA,IAAY,wBAAwB,EAAE,OAAO;GAChF,MAAM,EAAE;GACR,cAAc,EAAE;GAChB,YAAY,EAAE;EAChB,EAAE;EACF,cAAc,QAAQ,cAAc,YAAY,QAAQ,WAAW,IAAI,KAAA;CACzE;AACF;AAEA,IAAa,SAAb,MAAoB;CAClB,YAAY,QAAiC;EAAhB,KAAA,SAAA;CAAiB;CAE9C,MAAM,KACJ,SACA,gBAC4C;EAC5C,MAAM,eAAuC,CAAC;EAC9C,IAAI,gBAAgB,gBAClB,aAAa,qBAAqB,eAAe;EAEnD,MAAM,UAAU,MAAM,aAAa,OAAO;EAC1C,OAAO,KAAK,OAAO,KAAwB,WAAW,SAAS,YAAY;CAC7E;CAEA,MAAM,KAAK,UAA6B,CAAC,GAAgD;EACvF,MAAM,SAAS,IAAI,gBAAgB;EACnC,IAAI,QAAQ,SAAS,MAAM,OAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;EACpE,IAAI,QAAQ,QAAQ,OAAO,IAAI,UAAU,QAAQ,MAAM;EACvD,IAAI,QAAQ,QAAQ,OAAO,IAAI,UAAU,QAAQ,MAAM;EACvD,IAAI,QAAQ,MAAM,OAAO,IAAI,QAAQ,QAAQ,IAAI;EACjD,IAAI,QAAQ,IAAI,OAAO,IAAI,MAAM,QAAQ,EAAE;EAE3C,KAAK,MAAM,OAAO,QAAQ,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK,GAC9D,OAAO,OAAO,OAAO,GAAG;EAE1B,MAAM,KAAK,OAAO,SAAS;EAE3B,MAAM,MAAM,MAAM,KAAK,OAAO,IAC5B,KAAK,WAAW,OAAO,SACzB;EACA,IAAI,IAAI,OAAO,OAAO;EACtB,OAAO;GACL,MAAM;IAAE,MAAM,IAAI,KAAK;IAAM,YAAY,IAAI,KAAK;GAAY;GAC9D,OAAO;GACP,SAAS,IAAI;EACf;CACF;CAEA,IAAI,IAA4C;EAC9C,OAAO,KAAK,OAAO,IAAW,WAAW,IAAI;CAC/C;;;;;CAMA,MAAM,OACJ,IACA,SAC8C;EAC9C,MAAM,MAAM,MAAM,KAAK,OAAO,MAC5B,WAAW,MACX,EAAE,cAAc,YAAY,QAAQ,WAAW,EAAE,CACnD;EACA,IAAI,IAAI,OAAO,OAAO;EACtB,OAAO;GACL,MAAM;IAAE,IAAI,IAAI,KAAK;IAAI,QAAQ,IAAI,KAAK;IAAQ,aAAa,IAAI,KAAK;GAAa;GACrF,OAAO;GACP,SAAS,IAAI;EACf;CACF;;CAGA,OAAO,IAA0D;EAC/D,OAAO,KAAK,OAAO,KAA0B,WAAW,GAAG,UAAU,KAAA,CAAS;CAChF;AACF;;;;;;;;;;;;;;;;;;AClSA,IAAa,QAAb,MAAmB;CACjB,YAAY,QAAiC;EAAhB,KAAA,SAAA;CAAiB;CAE9C,MAAM,KACJ,QACA,gBAC4C;EAC5C,MAAM,eAAuC,CAAC;EAC9C,IAAI,gBAAgB,gBAClB,aAAa,qBAAqB,eAAe;EAEnD,MAAM,WAAW,MAAM,QAAQ,IAAI,OAAO,IAAI,YAAY,CAAC;EAC3D,OAAO,KAAK,OAAO,KAAwB,iBAAiB,UAAU,YAAY;CACpF;AACF;;;ACsDA,IAAa,UAAb,MAAqB;CACnB,YAAY,QAAiC;EAAhB,KAAA,SAAA;CAAiB;CAE9C,OAAO,MAA6D;EAClE,OAAO,KAAK,OAAO,KAA2B,YAAY,EAAE,KAAK,CAAC;CACpE;CAEA,OAAkD;EAChD,OAAO,KAAK,OAAO,IAAsB,UAAU;CACrD;CAEA,IAAI,IAA6C;EAC/C,OAAO,KAAK,OAAO,IAAY,YAAY,IAAI;CACjD;CAEA,OAAO,IAA2D;EAChE,OAAO,KAAK,OAAO,OAA6B,YAAY,IAAI;CAClE;CAEA,OAAO,IAA0D;EAC/D,OAAO,KAAK,OAAO,KAA0B,YAAY,GAAG,QAAQ;CACtE;AACF;;;ACzDA,IAAa,UAAb,MAAqB;CACnB,YAAY,QAAiC;EAAhB,KAAA,SAAA;CAAiB;CAE9C,MAAM,OAAO,SAA6E;EACxF,MAAM,MAAM,MAAM,KAAK,OAAO,KAA8B,aAAa;GACvE,MAAM,QAAQ;GACd,WAAW,QAAQ,YAAY;GAC/B,YAAY,QAAQ,cAAc;GAClC,GAAI,QAAQ,WAAW,EAAE,WAAW,QAAQ,SAAS,IAAI,CAAC;EAC5D,CAAC;EACD,IAAI,IAAI,OAAO,OAAO;EACtB,OAAO;GACL,MAAM;IACJ,IAAI,IAAI,KAAK;IACb,MAAM,IAAI,KAAK;IACf,KAAK,IAAI,KAAK;IACd,QAAQ,IAAI,KAAK;IACjB,UAAU,IAAI,KAAK;IACnB,YAAY,IAAI,KAAK;IACrB,UAAU,IAAI,KAAK;IACnB,YAAY,IAAI,KAAK;IACrB,WAAW,IAAI,KAAK;GACtB;GACA,OAAO;GACP,SAAS,IAAI;EACf;CACF;CAEA,OAA0C;EACxC,OAAO,KAAK,OAAO,IAAc,WAAW;CAC9C;CAEA,OAAO,IAA0D;EAC/D,OAAO,KAAK,OAAO,OAA4B,aAAa,IAAI;CAClE;AACF;;;ACgBA,IAAa,YAAb,MAAuB;CACrB,YAAY,QAAiC;EAAhB,KAAA,SAAA;CAAiB;CAE9C,OAAO,MAAiD;EACtD,OAAO,KAAK,OAAO,KAAe,cAAc,EAAE,KAAK,CAAC;CAC1D;CAEA,MAAM,OAAoD;EACxD,MAAM,MAAM,MAAM,KAAK,OAAO,IAAkC,YAAY;EAC5E,IAAI,IAAI,OAAO,OAAO;EACtB,OAAO;GAAE,MAAM,IAAI,KAAK;GAAM,OAAO;GAAM,SAAS,IAAI;EAAQ;CAClE;CAEA,IAAI,IAAqD;EACvD,OAAO,KAAK,OAAO,IAAoB,cAAc,IAAI;CAC3D;;CAGA,OAAO,IAAY,SAAmE;EACpF,OAAO,KAAK,OAAO,MAAgB,cAAc,MAAM,EAAE,MAAM,QAAQ,KAAK,CAAC;CAC/E;CAEA,OAAO,IAA4D;EACjE,OAAO,KAAK,OAAO,OAA8B,cAAc,IAAI;CACrE;CAEA,cACE,YACA,SACkC;EAClC,OAAO,KAAK,OAAO,KAAc,cAAc,WAAW,YAAY;GACpE,OAAO,QAAQ;GACf,YAAY,QAAQ;GACpB,WAAW,QAAQ;GACnB,YAAY,QAAQ;EACtB,CAAC;CACH;CAEA,MAAM,aACJ,YACA,UAA+B,CAAC,GACe;EAC/C,MAAM,SAAS,IAAI,gBAAgB;EACnC,IAAI,QAAQ,SAAS,MAAM,OAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;EACpE,IAAI,QAAQ,QAAQ,OAAO,IAAI,UAAU,QAAQ,MAAM;EACvD,IAAI,QAAQ,QAAQ,OAAO,IAAI,UAAU,QAAQ,MAAM;EACvD,IAAI,QAAQ,cAAc,MAAM,OAAO,IAAI,cAAc,OAAO,QAAQ,UAAU,CAAC;EACnF,MAAM,KAAK,OAAO,SAAS;EAC3B,OAAO,KAAK,OAAO,IACjB,KAAK,cAAc,WAAW,YAAY,OAAO,cAAc,WAAW,UAC5E;CACF;CAEA,WAAW,YAAoB,WAAqD;EAClF,OAAO,KAAK,OAAO,IAAa,cAAc,WAAW,YAAY,WAAW;CAClF;CAEA,cACE,YACA,WACA,SACkC;EAClC,OAAO,KAAK,OAAO,MAAe,cAAc,WAAW,YAAY,aAAa;GAClF,YAAY,QAAQ;GACpB,WAAW,QAAQ;GACnB,cAAc,QAAQ;GACtB,YAAY,QAAQ;EACtB,CAAC;CACH;CAEA,cACE,YACA,WACgD;EAChD,OAAO,KAAK,OAAO,OACjB,cAAc,WAAW,YAAY,WACvC;CACF;;;;;;;;;;;;;;;;;CAkBA,oBACE,YACA,YAC8C;EAC9C,OAAO,KAAK,OAAO,KACjB,cAAc,WAAW,yBACzB,EAAE,aAAa,WAAW,CAC5B;CACF;CAEA,oBACE,YACA,SACgE;EAChE,OAAO,KAAK,OAAO,KACjB,cAAc,WAAW,kBACzB,EACE,UAAU,QAAQ,SAAS,KAAK,OAAO;GACrC,OAAO,EAAE;GACT,YAAY,EAAE;GACd,WAAW,EAAE;GACb,cAAc,EAAE;GAChB,YAAY,EAAE;GACd,YAAY,EAAE;EAChB,EAAE,EACJ,CACF;CACF;AACF;;;;;;;;;;;ACpLA,IAAa,oBAAb,MAA+B;CAC7B,YAAY,QAAiC;EAAhB,KAAA,SAAA;CAAiB;CAE9C,OAAO,SAAiF;EACtF,OAAO,KAAK,OAAO,KAAsB,uBAAuB;GAC9D,KAAK,QAAQ;GACb,MAAM,QAAQ;GACd,gBAAgB,QAAQ;EAC1B,CAAC;CACH;;;CAIA,MAAM,OAAmD;EACvD,MAAM,MAAM,MAAM,KAAK,OAAO,IAAiC,qBAAqB;EACpF,IAAI,IAAI,OAAO,OAAO;EACtB,OAAO;GAAE,MAAM,IAAI,KAAK;GAAM,OAAO;GAAM,SAAS,IAAI;EAAQ;CAClE;CAEA,IAAI,IAAsD;EACxD,OAAO,KAAK,OAAO,IAAqB,uBAAuB,IAAI;CACrE;CAEA,OACE,IACA,SAC0C;EAC1C,OAAO,KAAK,OAAO,MAAuB,uBAAuB,MAAM,EACrE,gBAAgB,QAAQ,cAC1B,CAAC;CACH;;;;;;;;CASA,OAAO,IAAoE;EACzE,OAAO,KAAK,OAAO,OAAsC,uBAAuB,IAAI;CACtF;AACF;;;ACtCA,IAAa,SAAb,MAAoB;CAClB,YAAY,QAAiC;EAAhB,KAAA,SAAA;CAAiB;CAE9C,OAAO,SAA6D;EAClE,OAAO,KAAK,OAAO,KAAY,WAAW;GACxC,MAAM,QAAQ;GACd,sBAAsB,QAAQ;GAC9B,aAAa,QAAQ;GACrB,YAAY,QAAQ;EACtB,CAAC;CACH;;;CAIA,MAAM,OAAyC;EAC7C,MAAM,MAAM,MAAM,KAAK,OAAO,IAAuB,SAAS;EAC9D,IAAI,IAAI,OAAO,OAAO;EACtB,OAAO;GAAE,MAAM,IAAI,KAAK;GAAM,OAAO;GAAM,SAAS,IAAI;EAAQ;CAClE;CAEA,IAAI,IAA4C;EAC9C,OAAO,KAAK,OAAO,IAAW,WAAW,IAAI;CAC/C;CAEA,OAAO,IAAY,SAA6D;EAC9E,OAAO,KAAK,OAAO,MAAa,WAAW,MAAM;GAC/C,MAAM,QAAQ;GACd,aAAa,QAAQ;GACrB,YAAY,QAAQ;EACtB,CAAC;CACH;;;;CAKA,OAAO,IAA0D;EAC/D,OAAO,KAAK,OAAO,OAA4B,WAAW,IAAI;CAChE;;CAGA,UACE,SACA,WACA,aAAa,MACuC;EACpD,OAAO,KAAK,OAAO,IACjB,WAAW,QAAQ,YAAY,aAC/B,EAAE,WAAW,CACf;CACF;;;;;;;CAQA,kBACE,SACA,WACyD;EACzD,OAAO,KAAK,OAAO,OACjB,WAAW,QAAQ,YAAY,WACjC;CACF;AACF;;;AC7EA,eAAe,oBACb,SAC6B;CAC7B,IAAI,QAAQ,MAAM,OAAO,QAAQ;CACjC,IAAI,QAAQ,OAAO,OAAO,iBAAiB,QAAQ,KAAK;AAE1D;AAEA,IAAa,YAAb,MAAuB;CACrB,YAAY,QAAiC;EAAhB,KAAA,SAAA;CAAiB;CAE9C,MAAM,OAAO,SAAmE;EAC9E,MAAM,OAAO,MAAM,oBAAoB,OAAO;EAC9C,IAAI,CAAC,MACH,OAAO;GACL,MAAM;GACN,OAAO;IACL,SAAS;IACT,YAAY;IACZ,MAAM;GACR;GACA,SAAS;EACX;EAEF,OAAO,KAAK,OAAO,KAAe,cAAc;GAC9C,MAAM,QAAQ;GACd,SAAS,QAAQ;GACjB;EACF,CAAC;CACH;CAEA,MAAM,OAAoD;EACxD,MAAM,MAAM,MAAM,KAAK,OAAO,IAAkC,YAAY;EAC5E,IAAI,IAAI,OAAO,OAAO;EACtB,OAAO;GAAE,MAAM,IAAI,KAAK;GAAM,OAAO;GAAM,SAAS,IAAI;EAAQ;CAClE;CAEA,IAAI,IAA+C;EACjD,OAAO,KAAK,OAAO,IAAc,cAAc,IAAI;CACrD;CAEA,MAAM,OAAO,IAAY,SAAmE;EAC1F,MAAM,OAAO,MAAM,oBAAoB,OAAO;EAC9C,OAAO,KAAK,OAAO,MAAgB,cAAc,MAAM;GACrD,MAAM,QAAQ;GACd,SAAS,QAAQ;GACjB;EACF,CAAC;CACH;CAEA,OAAO,IAA4D;EACjE,OAAO,KAAK,OAAO,OAA8B,cAAc,IAAI;CACrE;AACF;;;AC5CA,IAAa,WAAb,MAAsB;CACpB,YAAY,QAAiC;EAAhB,KAAA,SAAA;CAAiB;CAE9C,OAAO,SAA+E;EACpF,OAAO,KAAK,OAAO,KAA4B,aAAa;GAC1D,KAAK,QAAQ;GACb,QAAQ,QAAQ;EAClB,CAAC;CACH;CAEA,MAAM,OAA2C;EAC/C,MAAM,MAAM,MAAM,KAAK,OAAO,IAAyB,WAAW;EAClE,IAAI,IAAI,OAAO,OAAO;EACtB,OAAO;GAAE,MAAM,IAAI,KAAK;GAAM,OAAO;GAAM,SAAS,IAAI;EAAQ;CAClE;CAEA,IAAI,IAA4D;EAC9D,OAAO,KAAK,OAAO,IAA2B,aAAa,IAAI;CACjE;CAEA,OAAO,IAAY,SAAiE;EAClF,OAAO,KAAK,OAAO,MAAe,aAAa,MAAM;GACnD,KAAK,QAAQ;GACb,QAAQ,QAAQ;EAClB,CAAC;CACH;CAEA,OAAO,IAA4D;EACjE,OAAO,KAAK,OAAO,OAA8B,aAAa,IAAI;CACpE;AACF;;;ACyEA,eAAe,qBAAqB,SAGJ;CAC9B,IAAI,QAAQ,MAAM,OAAO,QAAQ;CACjC,IAAI,QAAQ,OAAO,OAAO,iBAAiB,QAAQ,KAAK;AAE1D;AAEA,IAAa,aAAb,MAAwB;CACtB,YAAY,QAAiC;EAAhB,KAAA,SAAA;CAAiB;CAE9C,MAAM,OAAO,SAAqE;EAChF,MAAM,OAAO,MAAM,qBAAqB,OAAO;EAC/C,OAAO,KAAK,OAAO,KAAgB,eAAe;GAChD,MAAM,QAAQ;GACd,aAAa,QAAQ;GACrB,UAAU,QAAQ;GAClB,MAAM,QAAQ;GACd,UAAU,QAAQ;GAClB,SAAS,QAAQ;GACjB;GACA,aAAa,QAAQ;GACrB,oBAAoB,QAAQ;GAC5B,aAAa,QAAQ;GACrB,cAAc,QAAQ;EACxB,CAAC;CACH;CAEA,MAAM,OAAqD;EACzD,MAAM,MAAM,MAAM,KAAK,OAAO,IAAmC,aAAa;EAC9E,IAAI,IAAI,OAAO,OAAO;EACtB,OAAO;GAAE,MAAM,IAAI,KAAK;GAAM,OAAO;GAAM,SAAS,IAAI;EAAQ;CAClE;CAEA,IAAI,IAAsD;EACxD,OAAO,KAAK,OAAO,IAAqB,eAAe,IAAI;CAC7D;;;;;;CAOA,MAAM,OAAO,IAAY,SAAqE;EAC5F,MAAM,OAAO,MAAM,qBAAqB,OAAO;EAC/C,OAAO,KAAK,OAAO,MAAiB,eAAe,MAAM;GACvD,MAAM,QAAQ;GACd,aAAa,QAAQ;GACrB,UAAU,QAAQ;GAClB,MAAM,QAAQ;GACd,UAAU,QAAQ;GAClB,SAAS,QAAQ;GACjB;GACA,aAAa,QAAQ;GACrB,oBAAoB,QAAQ;GAC5B,cAAc,QAAQ;GACtB,aAAa,QAAQ;GACrB,cAAc,QAAQ;EACxB,CAAC;CACH;CAEA,MAAM,KACJ,IACA,UAAgC,CAAC,GACe;EAGhD,MAAM,MAAM,MAAM,KAAK,OAAO,KAI3B,eAAe,GAAG,QAAQ,EAC3B,cAAc,QAAQ,YACxB,CAAC;EACD,IAAI,IAAI,OAAO,OAAO;EACtB,OAAO;GACL,MAAM;IAAE,IAAI,IAAI,KAAK;IAAI,QAAQ,IAAI,KAAK;IAAQ,aAAa,IAAI,KAAK;GAAa;GACrF,OAAO;GACP,SAAS,IAAI;EACf;CACF;;;;;;;;;;;;CAaA,MAAM,KACJ,IACA,SACgD;EAEhD,MAAM,MAAM,MAAM,KAAK,OAAO,KAI3B,eAAe,GAAG,QAAQ,EAAE,IAAI,QAAQ,GAAG,CAAC;EAC/C,IAAI,IAAI,OAAO,OAAO;EACtB,OAAO;GACL,MAAM;IAAE,IAAI,IAAI,KAAK;IAAI,QAAQ,IAAI,KAAK;IAAS,UAAU,IAAI,KAAK;GAAU;GAChF,OAAO;GACP,SAAS,IAAI;EACf;CACF;CAEA,OAAO,IAAgD;EACrD,OAAO,KAAK,OAAO,KAAgB,eAAe,GAAG,QAAQ;CAC/D;CAEA,OAAO,IAA4D;EACjE,OAAO,KAAK,OAAO,OAA8B,eAAe,IAAI;CACtE;AACF;;;;;;;;;;AChOA,IAAa,eAAb,MAA0B;CACxB,YAAY,QAAiC;EAAhB,KAAA,SAAA;CAAiB;CAE9C,KAAK,UAAmC,CAAC,GAAsD;EAC7F,MAAM,SAAS,IAAI,gBAAgB;EACnC,IAAI,QAAQ,OAAO,OAAO,IAAI,SAAS,QAAQ,KAAK;EACpD,IAAI,QAAQ,QAAQ,OAAO,IAAI,UAAU,QAAQ,MAAM;EACvD,IAAI,QAAQ,SAAS,MAAM,OAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;EACpE,IAAI,QAAQ,QAAQ,OAAO,IAAI,UAAU,QAAQ,MAAM;EACvD,MAAM,KAAK,OAAO,SAAS;EAC3B,OAAO,KAAK,OAAO,IAA8B,KAAK,iBAAiB,OAAO,eAAe;CAC/F;;;;;CAMA,OAAO,SAA8E;EACnF,OAAO,KAAK,OAAO,KAAuB,iBAAiB;GACzD,OAAO,QAAQ;GACf,QAAQ,QAAQ;EAClB,CAAC;CACH;;;;;CAMA,OAAO,QAAsF;EAC3F,OAAO,KAAK,OAAO,KAAiC,uBAAuB,EAAE,OAAO,CAAC;CACvF;;;;;;;;CASA,OAAO,WAAiE;EACtE,OAAO,KAAK,OAAO,OAA4B,iBAAiB,mBAAmB,SAAS,GAAG;CACjG;;CAGA,SAA0C;EACxC,OAAO,KAAK,OAAO,aAAqB,wBAAwB,EAAE,QAAQ,MAAM,GAAG,CAAC,GAAG,MAAM;CAC/F;AACF;;;ACpFA,MAAM,mBAAmB;AACzB,MAAM,cAAc;AAMpB,IAAa,SAAb,MAAoB;CAmBlB,YAAY,KAAc,SAAyB;EACjD,MAAM,SACJ,QAAQ,OAAO,YAAY,cAAc,QAAQ,IAAI,oBAAoB,KAAA;EAC3E,IAAI,CAAC,QACH,MAAM,IAAI,MACR,oGACF;EAEF,KAAK,SAAS;EACd,KAAK,UAAU,SAAS,WAAW;EAEnC,KAAK,SAAS,IAAI,OAAO,IAAI;EAC7B,KAAK,QAAQ,IAAI,MAAM,IAAI;EAC3B,KAAK,UAAU,IAAI,QAAQ,IAAI;EAC/B,KAAK,UAAU,IAAI,QAAQ,IAAI;EAC/B,KAAK,YAAY,IAAI,UAAU,IAAI;EACnC,KAAK,oBAAoB,IAAI,kBAAkB,IAAI;EACnD,KAAK,SAAS,IAAI,OAAO,IAAI;EAC7B,KAAK,YAAY,IAAI,UAAU,IAAI;EACnC,KAAK,WAAW,IAAI,SAAS,IAAI;EACjC,KAAK,aAAa,IAAI,WAAW,IAAI;EACrC,KAAK,eAAe,IAAI,aAAa,IAAI;CAC3C;CAEA,MAAM,aACJ,MACA,OAAoB,CAAC,GACrB,eAAuC,CAAC,GAIxC,QAAyB,QACG;EAC5B,MAAM,UAAkC;GACtC,eAAe,UAAU,KAAK;GAC9B,gBAAgB;GAChB,cAAc,eAAe;GAC7B,GAAG;EACL;EAEA,IAAI;GACF,MAAM,MAAM,MAAM,MAAM,GAAG,KAAK,UAAU,QAAQ;IAAE,GAAG;IAAM;GAAQ,CAAC;GACtE,MAAM,kBAAkB,OAAO,YAAY,IAAI,QAAQ,QAAQ,CAAC;GAEhE,IAAI,CAAC,IAAI,IAAI;IACX,IAAI;IACJ,IAAI;KACF,MAAM,OAAQ,MAAM,IAAI,KAAK;KAC7B,QAAQ;MACN,SAAS,KAAK,SAAS;MACvB,YAAY,IAAI;MAChB,MAAO,KAAK,QAAgC;KAC9C;IACF,QAAQ;KACN,QAAQ;MAAE,SAAS;MAAkB,YAAY,IAAI;MAAQ,MAAM;KAAiB;IACtF;IACA,OAAO;KAAE,MAAM;KAAM;KAAO,SAAS;IAAgB;GACvD;GAEA,IAAI,IAAI,WAAW,OAAO,IAAI,QAAQ,IAAI,gBAAgB,MAAM,KAC9D,OAAO;IAAE,MAAM,CAAC;IAAQ,OAAO;IAAM,SAAS;GAAgB;GAIhE,OAAO;IAAE,MADK,UAAU,SAAS,MAAM,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK;IACpD,OAAO;IAAM,SAAS;GAAgB;EACvD,QAAQ;GACN,OAAO;IACL,MAAM;IACN,OAAO;KACL,SAAS;KACT,YAAY;KACZ,MAAM;IACR;IACA,SAAS;GACX;EACF;CACF;CAEA,IAAO,MAAc,cAAmE;EACtF,OAAO,KAAK,aAAgB,MAAM,EAAE,QAAQ,MAAM,GAAG,YAAY;CACnE;CAEA,KACE,MACA,MACA,cAC4B;EAC5B,OAAO,KAAK,aACV,MACA;GAAE,QAAQ;GAAQ,MAAM,QAAQ,OAAO,KAAK,UAAU,IAAI,IAAI,KAAA;EAAU,GACxE,YACF;CACF;CAEA,MAAS,MAAc,MAA4C;EACjE,OAAO,KAAK,aAAgB,MAAM;GAChC,QAAQ;GACR,MAAM,QAAQ,OAAO,KAAK,UAAU,IAAI,IAAI,KAAA;EAC9C,CAAC;CACH;CAEA,IAAO,MAAc,MAA4C;EAC/D,OAAO,KAAK,aAAgB,MAAM;GAChC,QAAQ;GACR,MAAM,QAAQ,OAAO,KAAK,UAAU,IAAI,IAAI,KAAA;EAC9C,CAAC;CACH;CAEA,OAAU,MAA0C;EAClD,OAAO,KAAK,aAAgB,MAAM,EAAE,QAAQ,SAAS,CAAC;CACxD;AACF"}
|