@eusend_dev/sdk 0.15.1 → 0.17.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 +47 -0
- package/dist/index.cjs +114 -1
- package/dist/index.d.cts +146 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +146 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +114 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -369,6 +369,53 @@ await client.audiences.deleteContact(audienceId, contactId)
|
|
|
369
369
|
|
|
370
370
|
---
|
|
371
371
|
|
|
372
|
+
## Contact properties
|
|
373
|
+
|
|
374
|
+
The custom fields your contacts carry — the `{{variables}}` a broadcast can personalize on.
|
|
375
|
+
|
|
376
|
+
Declaring a property is optional: one you send on a contact without ever declaring it
|
|
377
|
+
registers itself as a `string`, so existing code needs no changes. Declaring it is what
|
|
378
|
+
gives it a type and a fallback value.
|
|
379
|
+
|
|
380
|
+
### Declare a property
|
|
381
|
+
|
|
382
|
+
```ts
|
|
383
|
+
await client.contactProperties.create({
|
|
384
|
+
key: 'plan',
|
|
385
|
+
type: 'string', // or 'number' — a write-time check, not formatting
|
|
386
|
+
fallbackValue: 'free', // rendered for contacts with no value of their own
|
|
387
|
+
})
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### List properties
|
|
391
|
+
|
|
392
|
+
```ts
|
|
393
|
+
const { data } = await client.contactProperties.list()
|
|
394
|
+
// [{ id, key, type, fallbackValue, createdAt, updatedAt }]
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Update a property
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
await client.contactProperties.update(propertyId, { fallbackValue: 'trial' })
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
The fallback is the only mutable field. Renaming or retyping would have to rewrite every
|
|
404
|
+
contact *and* every broadcast body spelling `{{old_key}}`, so both are a delete and a
|
|
405
|
+
create.
|
|
406
|
+
|
|
407
|
+
### Delete a property
|
|
408
|
+
|
|
409
|
+
```ts
|
|
410
|
+
const { data } = await client.contactProperties.delete(propertyId)
|
|
411
|
+
// { deleted: true, contactsUpdated: 1240 }
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Deletes the definition **and** strips the key from every contact in the organization. Not
|
|
415
|
+
undoable.
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
372
419
|
## Suppressions
|
|
373
420
|
|
|
374
421
|
Addresses the account will not send to. Hard bounces and spam complaints are added
|
package/dist/index.cjs
CHANGED
|
@@ -275,6 +275,109 @@ var Audiences = class {
|
|
|
275
275
|
}
|
|
276
276
|
};
|
|
277
277
|
//#endregion
|
|
278
|
+
//#region src/contact-properties.ts
|
|
279
|
+
/**
|
|
280
|
+
* The organization's custom contact properties — the schema behind the `properties` bag
|
|
281
|
+
* each contact carries.
|
|
282
|
+
*
|
|
283
|
+
* Declaring a property is optional. A property arriving on a contact write that has never
|
|
284
|
+
* been declared registers itself as a `string`, so an existing integration needs no
|
|
285
|
+
* changes. Declaring one up front is what buys a type check and a fallback value.
|
|
286
|
+
*/
|
|
287
|
+
var ContactProperties = class {
|
|
288
|
+
constructor(client) {
|
|
289
|
+
this.client = client;
|
|
290
|
+
}
|
|
291
|
+
create(options) {
|
|
292
|
+
return this.client.post("/contact-properties", {
|
|
293
|
+
key: options.key,
|
|
294
|
+
type: options.type,
|
|
295
|
+
fallback_value: options.fallbackValue
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
/** Every property the organization has defined. Unpaginated — the registry is capped at
|
|
299
|
+
* 100 entries, and a variable picker wants all of them. */
|
|
300
|
+
async list() {
|
|
301
|
+
const res = await this.client.get("/contact-properties");
|
|
302
|
+
if (res.error) return res;
|
|
303
|
+
return {
|
|
304
|
+
data: res.data.data,
|
|
305
|
+
error: null,
|
|
306
|
+
headers: res.headers
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
get(id) {
|
|
310
|
+
return this.client.get(`/contact-properties/${id}`);
|
|
311
|
+
}
|
|
312
|
+
update(id, options) {
|
|
313
|
+
return this.client.patch(`/contact-properties/${id}`, { fallback_value: options.fallbackValue });
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Delete a property definition AND strip the key from every contact in the organization.
|
|
317
|
+
*
|
|
318
|
+
* Destructive and not undoable. Leaving the values in place was the alternative, and a
|
|
319
|
+
* worse one: the property would keep rendering in broadcasts, and the next contact write
|
|
320
|
+
* carrying that key would register it again.
|
|
321
|
+
*/
|
|
322
|
+
delete(id) {
|
|
323
|
+
return this.client.delete(`/contact-properties/${id}`);
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
//#endregion
|
|
327
|
+
//#region src/topics.ts
|
|
328
|
+
var Topics = class {
|
|
329
|
+
constructor(client) {
|
|
330
|
+
this.client = client;
|
|
331
|
+
}
|
|
332
|
+
create(options) {
|
|
333
|
+
return this.client.post("/topics", {
|
|
334
|
+
name: options.name,
|
|
335
|
+
default_subscription: options.defaultSubscription,
|
|
336
|
+
description: options.description,
|
|
337
|
+
visibility: options.visibility
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
/** Every topic the organization has defined. Unpaginated — the list is capped at 100,
|
|
341
|
+
* and both the composer's picker and the unsubscribe page want all of it. */
|
|
342
|
+
async list() {
|
|
343
|
+
const res = await this.client.get("/topics");
|
|
344
|
+
if (res.error) return res;
|
|
345
|
+
return {
|
|
346
|
+
data: res.data.data,
|
|
347
|
+
error: null,
|
|
348
|
+
headers: res.headers
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
get(id) {
|
|
352
|
+
return this.client.get(`/topics/${id}`);
|
|
353
|
+
}
|
|
354
|
+
update(id, options) {
|
|
355
|
+
return this.client.patch(`/topics/${id}`, {
|
|
356
|
+
name: options.name,
|
|
357
|
+
description: options.description,
|
|
358
|
+
visibility: options.visibility
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
/** Deletes the topic and every stored preference for it. A draft or scheduled broadcast
|
|
362
|
+
* scoped to it widens back to its whole audience. */
|
|
363
|
+
delete(id) {
|
|
364
|
+
return this.client.delete(`/topics/${id}`);
|
|
365
|
+
}
|
|
366
|
+
/** Record an explicit preference for one contact. */
|
|
367
|
+
subscribe(topicId, contactId, subscribed = true) {
|
|
368
|
+
return this.client.put(`/topics/${topicId}/contacts/${contactId}`, { subscribed });
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Forget the contact's explicit choice, so they fall back to the topic's default.
|
|
372
|
+
*
|
|
373
|
+
* Different from `subscribe(id, contactId, false)`: that records "no thanks", this
|
|
374
|
+
* records nothing at all — so on an opt-in topic the contact starts receiving it again.
|
|
375
|
+
*/
|
|
376
|
+
clearSubscription(topicId, contactId) {
|
|
377
|
+
return this.client.delete(`/topics/${topicId}/contacts/${contactId}`);
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
//#endregion
|
|
278
381
|
//#region src/templates.ts
|
|
279
382
|
async function resolveTemplateHtml(options) {
|
|
280
383
|
if (options.html) return options.html;
|
|
@@ -374,6 +477,7 @@ var Broadcasts = class {
|
|
|
374
477
|
return this.client.post("/broadcasts", {
|
|
375
478
|
name: options.name,
|
|
376
479
|
audience_id: options.audienceId,
|
|
480
|
+
topic_id: options.topicId,
|
|
377
481
|
from: options.from,
|
|
378
482
|
subject: options.subject,
|
|
379
483
|
html,
|
|
@@ -400,6 +504,7 @@ var Broadcasts = class {
|
|
|
400
504
|
return this.client.patch(`/broadcasts/${id}`, {
|
|
401
505
|
name: options.name,
|
|
402
506
|
audience_id: options.audienceId,
|
|
507
|
+
topic_id: options.topicId,
|
|
403
508
|
from: options.from,
|
|
404
509
|
subject: options.subject,
|
|
405
510
|
html,
|
|
@@ -511,7 +616,7 @@ var Suppressions = class {
|
|
|
511
616
|
//#endregion
|
|
512
617
|
//#region src/eusend.ts
|
|
513
618
|
const DEFAULT_BASE_URL = "https://api.eusend.dev";
|
|
514
|
-
const SDK_VERSION = "0.
|
|
619
|
+
const SDK_VERSION = "0.17.0";
|
|
515
620
|
var Eusend = class {
|
|
516
621
|
constructor(key, options) {
|
|
517
622
|
const apiKey = key ?? (typeof process !== "undefined" ? process.env["EUSEND_API_KEY"] : void 0);
|
|
@@ -523,6 +628,8 @@ var Eusend = class {
|
|
|
523
628
|
this.domains = new Domains(this);
|
|
524
629
|
this.apiKeys = new ApiKeys(this);
|
|
525
630
|
this.audiences = new Audiences(this);
|
|
631
|
+
this.contactProperties = new ContactProperties(this);
|
|
632
|
+
this.topics = new Topics(this);
|
|
526
633
|
this.templates = new Templates(this);
|
|
527
634
|
this.webhooks = new Webhooks(this);
|
|
528
635
|
this.broadcasts = new Broadcasts(this);
|
|
@@ -600,6 +707,12 @@ var Eusend = class {
|
|
|
600
707
|
body: body != null ? JSON.stringify(body) : void 0
|
|
601
708
|
});
|
|
602
709
|
}
|
|
710
|
+
put(path, body) {
|
|
711
|
+
return this.fetchRequest(path, {
|
|
712
|
+
method: "PUT",
|
|
713
|
+
body: body != null ? JSON.stringify(body) : void 0
|
|
714
|
+
});
|
|
715
|
+
}
|
|
603
716
|
delete(path) {
|
|
604
717
|
return this.fetchRequest(path, { method: "DELETE" });
|
|
605
718
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -493,6 +493,137 @@ declare class Audiences {
|
|
|
493
493
|
}>>;
|
|
494
494
|
}
|
|
495
495
|
//#endregion
|
|
496
|
+
//#region src/contact-properties.d.ts
|
|
497
|
+
/**
|
|
498
|
+
* A declared property's type. Values are carried and rendered as strings either way —
|
|
499
|
+
* `number` buys a write-time check, not arithmetic or locale formatting.
|
|
500
|
+
*/
|
|
501
|
+
type ContactPropertyType = 'string' | 'number';
|
|
502
|
+
interface ContactProperty {
|
|
503
|
+
id: string;
|
|
504
|
+
key: string;
|
|
505
|
+
type: ContactPropertyType;
|
|
506
|
+
/** Substituted into `{{key}}` for contacts that carry no value of their own. `null`
|
|
507
|
+
* renders empty, which is what an unset property did before the registry existed. */
|
|
508
|
+
fallbackValue: string | null;
|
|
509
|
+
createdAt: string;
|
|
510
|
+
updatedAt: string;
|
|
511
|
+
}
|
|
512
|
+
interface CreateContactPropertyOptions {
|
|
513
|
+
/** Lowercase letters, digits and underscores, starting with a letter; at most 40
|
|
514
|
+
* characters. `email`, `name`, `first_name`, `last_name` and `full_name` are built in
|
|
515
|
+
* and cannot be declared. */
|
|
516
|
+
key: string;
|
|
517
|
+
/** Defaults to `string`. */
|
|
518
|
+
type?: ContactPropertyType;
|
|
519
|
+
fallbackValue?: string | null;
|
|
520
|
+
}
|
|
521
|
+
interface UpdateContactPropertyOptions {
|
|
522
|
+
/** The only mutable field. `key` and `type` are fixed at creation: a rename would have
|
|
523
|
+
* to rewrite every contact and every broadcast body spelling `{{old_key}}`, so changing
|
|
524
|
+
* either is a delete and a create. */
|
|
525
|
+
fallbackValue: string | null;
|
|
526
|
+
}
|
|
527
|
+
interface DeleteContactPropertyResponse {
|
|
528
|
+
deleted: true;
|
|
529
|
+
/** How many contacts had the key stripped from them. */
|
|
530
|
+
contactsUpdated: number;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* The organization's custom contact properties — the schema behind the `properties` bag
|
|
534
|
+
* each contact carries.
|
|
535
|
+
*
|
|
536
|
+
* Declaring a property is optional. A property arriving on a contact write that has never
|
|
537
|
+
* been declared registers itself as a `string`, so an existing integration needs no
|
|
538
|
+
* changes. Declaring one up front is what buys a type check and a fallback value.
|
|
539
|
+
*/
|
|
540
|
+
declare class ContactProperties {
|
|
541
|
+
private readonly client;
|
|
542
|
+
constructor(client: Eusend);
|
|
543
|
+
create(options: CreateContactPropertyOptions): Promise<EusendResponse<ContactProperty>>;
|
|
544
|
+
/** Every property the organization has defined. Unpaginated — the registry is capped at
|
|
545
|
+
* 100 entries, and a variable picker wants all of them. */
|
|
546
|
+
list(): Promise<EusendResponse<ContactProperty[]>>;
|
|
547
|
+
get(id: string): Promise<EusendResponse<ContactProperty>>;
|
|
548
|
+
update(id: string, options: UpdateContactPropertyOptions): Promise<EusendResponse<ContactProperty>>;
|
|
549
|
+
/**
|
|
550
|
+
* Delete a property definition AND strip the key from every contact in the organization.
|
|
551
|
+
*
|
|
552
|
+
* Destructive and not undoable. Leaving the values in place was the alternative, and a
|
|
553
|
+
* worse one: the property would keep rendering in broadcasts, and the next contact write
|
|
554
|
+
* carrying that key would register it again.
|
|
555
|
+
*/
|
|
556
|
+
delete(id: string): Promise<EusendResponse<DeleteContactPropertyResponse>>;
|
|
557
|
+
}
|
|
558
|
+
//#endregion
|
|
559
|
+
//#region src/topics.d.ts
|
|
560
|
+
/** What a contact who has never expressed a preference receives. Fixed at creation. */
|
|
561
|
+
type TopicDefaultSubscription = 'opt_in' | 'opt_out';
|
|
562
|
+
/** Whether the topic is listed on the unsubscribe page to a contact who is not opted in. */
|
|
563
|
+
type TopicVisibility = 'public' | 'private';
|
|
564
|
+
interface Topic {
|
|
565
|
+
id: string;
|
|
566
|
+
name: string;
|
|
567
|
+
description: string | null;
|
|
568
|
+
defaultSubscription: TopicDefaultSubscription;
|
|
569
|
+
visibility: TopicVisibility;
|
|
570
|
+
/** Contacts who explicitly opted in. Present on list and create, not on get. */
|
|
571
|
+
subscriberCount?: number;
|
|
572
|
+
createdAt: string;
|
|
573
|
+
updatedAt: string;
|
|
574
|
+
}
|
|
575
|
+
interface CreateTopicOptions {
|
|
576
|
+
name: string;
|
|
577
|
+
/** `opt_in` reaches everyone until they leave; `opt_out` reaches nobody until they join.
|
|
578
|
+
* Cannot be changed afterwards. */
|
|
579
|
+
defaultSubscription: TopicDefaultSubscription;
|
|
580
|
+
description?: string | null;
|
|
581
|
+
/** Defaults to `private`. */
|
|
582
|
+
visibility?: TopicVisibility;
|
|
583
|
+
}
|
|
584
|
+
/** `defaultSubscription` is absent deliberately — it is fixed at creation. */
|
|
585
|
+
interface UpdateTopicOptions {
|
|
586
|
+
name?: string;
|
|
587
|
+
description?: string | null;
|
|
588
|
+
visibility?: TopicVisibility;
|
|
589
|
+
}
|
|
590
|
+
interface DeleteTopicResponse {
|
|
591
|
+
id: string;
|
|
592
|
+
deleted: true;
|
|
593
|
+
}
|
|
594
|
+
interface TopicSubscriptionResponse {
|
|
595
|
+
topicId: string;
|
|
596
|
+
contactId: string;
|
|
597
|
+
subscribed: boolean;
|
|
598
|
+
}
|
|
599
|
+
interface ClearTopicSubscriptionResponse {
|
|
600
|
+
topicId: string;
|
|
601
|
+
contactId: string;
|
|
602
|
+
deleted: true;
|
|
603
|
+
}
|
|
604
|
+
declare class Topics {
|
|
605
|
+
private readonly client;
|
|
606
|
+
constructor(client: Eusend);
|
|
607
|
+
create(options: CreateTopicOptions): Promise<EusendResponse<Topic>>;
|
|
608
|
+
/** Every topic the organization has defined. Unpaginated — the list is capped at 100,
|
|
609
|
+
* and both the composer's picker and the unsubscribe page want all of it. */
|
|
610
|
+
list(): Promise<EusendResponse<Topic[]>>;
|
|
611
|
+
get(id: string): Promise<EusendResponse<Topic>>;
|
|
612
|
+
update(id: string, options: UpdateTopicOptions): Promise<EusendResponse<Topic>>;
|
|
613
|
+
/** Deletes the topic and every stored preference for it. A draft or scheduled broadcast
|
|
614
|
+
* scoped to it widens back to its whole audience. */
|
|
615
|
+
delete(id: string): Promise<EusendResponse<DeleteTopicResponse>>;
|
|
616
|
+
/** Record an explicit preference for one contact. */
|
|
617
|
+
subscribe(topicId: string, contactId: string, subscribed?: boolean): Promise<EusendResponse<TopicSubscriptionResponse>>;
|
|
618
|
+
/**
|
|
619
|
+
* Forget the contact's explicit choice, so they fall back to the topic's default.
|
|
620
|
+
*
|
|
621
|
+
* Different from `subscribe(id, contactId, false)`: that records "no thanks", this
|
|
622
|
+
* records nothing at all — so on an opt-in topic the contact starts receiving it again.
|
|
623
|
+
*/
|
|
624
|
+
clearSubscription(topicId: string, contactId: string): Promise<EusendResponse<ClearTopicSubscriptionResponse>>;
|
|
625
|
+
}
|
|
626
|
+
//#endregion
|
|
496
627
|
//#region src/templates.d.ts
|
|
497
628
|
interface TemplateHtmlOrReact {
|
|
498
629
|
/**
|
|
@@ -591,6 +722,9 @@ type BroadcastStatus = 'draft' | 'scheduled' | 'sending' | 'sent' | 'paused' | '
|
|
|
591
722
|
interface CreateBroadcastOptions {
|
|
592
723
|
name: string;
|
|
593
724
|
audienceId: string;
|
|
725
|
+
/** Narrows the audience to the contacts subscribed to this topic. Omit to send to all
|
|
726
|
+
* of it. */
|
|
727
|
+
topicId?: string;
|
|
594
728
|
/**
|
|
595
729
|
* Sender address. Accepts a bare email (`onboarding@eusend.dev`) or a display-name
|
|
596
730
|
* form (`Acme <onboarding@eusend.dev>`). The domain must be verified on your account.
|
|
@@ -620,6 +754,8 @@ interface CreateBroadcastOptions {
|
|
|
620
754
|
interface UpdateBroadcastOptions {
|
|
621
755
|
name?: string;
|
|
622
756
|
audienceId?: string;
|
|
757
|
+
/** Pass null to clear the topic and widen the send back to the whole audience. */
|
|
758
|
+
topicId?: string | null;
|
|
623
759
|
from?: string;
|
|
624
760
|
subject?: string;
|
|
625
761
|
html?: string;
|
|
@@ -651,6 +787,8 @@ interface Broadcast {
|
|
|
651
787
|
status: BroadcastStatus;
|
|
652
788
|
/** Null when the associated audience has been deleted. */
|
|
653
789
|
audienceId: string | null;
|
|
790
|
+
/** The topic this broadcast is scoped to, or null for the whole audience. */
|
|
791
|
+
topicId: string | null;
|
|
654
792
|
fromAddress: string;
|
|
655
793
|
replyTo: string | null;
|
|
656
794
|
subject: string;
|
|
@@ -676,6 +814,8 @@ interface BroadcastListItem {
|
|
|
676
814
|
status: BroadcastStatus;
|
|
677
815
|
/** Null when the associated audience has been deleted. */
|
|
678
816
|
audienceId: string | null;
|
|
817
|
+
topicId: string | null;
|
|
818
|
+
topicName: string | null;
|
|
679
819
|
fromAddress: string;
|
|
680
820
|
subject: string;
|
|
681
821
|
recipientCount: number | null;
|
|
@@ -819,6 +959,10 @@ declare class Eusend {
|
|
|
819
959
|
readonly domains: Domains;
|
|
820
960
|
readonly apiKeys: ApiKeys;
|
|
821
961
|
readonly audiences: Audiences;
|
|
962
|
+
/** The org's declared contact properties — `client.contactProperties.list()`. */
|
|
963
|
+
readonly contactProperties: ContactProperties;
|
|
964
|
+
/** Subscription topics — `client.topics.list()`. */
|
|
965
|
+
readonly topics: Topics;
|
|
822
966
|
readonly templates: Templates;
|
|
823
967
|
readonly webhooks: Webhooks;
|
|
824
968
|
readonly broadcasts: Broadcasts;
|
|
@@ -828,8 +972,9 @@ declare class Eusend {
|
|
|
828
972
|
get<T>(path: string, extraHeaders?: Record<string, string>): Promise<EusendResponse<T>>;
|
|
829
973
|
post<T>(path: string, body?: unknown, extraHeaders?: Record<string, string>): Promise<EusendResponse<T>>;
|
|
830
974
|
patch<T>(path: string, body?: unknown): Promise<EusendResponse<T>>;
|
|
975
|
+
put<T>(path: string, body?: unknown): Promise<EusendResponse<T>>;
|
|
831
976
|
delete<T>(path: string): Promise<EusendResponse<T>>;
|
|
832
977
|
}
|
|
833
978
|
//#endregion
|
|
834
|
-
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 Contact, type ContactStatus, type CreateApiKeyOptions, type CreateApiKeyResponse, type CreateBroadcastOptions, type CreateContactOptions, type CreateDomainResponse, type CreateSuppressionOptions, type CreateTemplateOptions, type CreateWebhookOptions, type CreateWebhookResponse, 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 UpdateBroadcastOptions, type UpdateContactOptions, type UpdateEmailOptions, type UpdateEmailResponse, type UpdateTemplateOptions, type UpdateWebhookOptions, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookWithDeliveries };
|
|
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 };
|
|
835
980
|
//# 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/templates.ts","../src/webhooks.ts","../src/broadcasts.ts","../src/suppressions.ts","../src/eusend.ts"],"mappings":"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
|
|
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
|
@@ -493,6 +493,137 @@ declare class Audiences {
|
|
|
493
493
|
}>>;
|
|
494
494
|
}
|
|
495
495
|
//#endregion
|
|
496
|
+
//#region src/contact-properties.d.ts
|
|
497
|
+
/**
|
|
498
|
+
* A declared property's type. Values are carried and rendered as strings either way —
|
|
499
|
+
* `number` buys a write-time check, not arithmetic or locale formatting.
|
|
500
|
+
*/
|
|
501
|
+
type ContactPropertyType = 'string' | 'number';
|
|
502
|
+
interface ContactProperty {
|
|
503
|
+
id: string;
|
|
504
|
+
key: string;
|
|
505
|
+
type: ContactPropertyType;
|
|
506
|
+
/** Substituted into `{{key}}` for contacts that carry no value of their own. `null`
|
|
507
|
+
* renders empty, which is what an unset property did before the registry existed. */
|
|
508
|
+
fallbackValue: string | null;
|
|
509
|
+
createdAt: string;
|
|
510
|
+
updatedAt: string;
|
|
511
|
+
}
|
|
512
|
+
interface CreateContactPropertyOptions {
|
|
513
|
+
/** Lowercase letters, digits and underscores, starting with a letter; at most 40
|
|
514
|
+
* characters. `email`, `name`, `first_name`, `last_name` and `full_name` are built in
|
|
515
|
+
* and cannot be declared. */
|
|
516
|
+
key: string;
|
|
517
|
+
/** Defaults to `string`. */
|
|
518
|
+
type?: ContactPropertyType;
|
|
519
|
+
fallbackValue?: string | null;
|
|
520
|
+
}
|
|
521
|
+
interface UpdateContactPropertyOptions {
|
|
522
|
+
/** The only mutable field. `key` and `type` are fixed at creation: a rename would have
|
|
523
|
+
* to rewrite every contact and every broadcast body spelling `{{old_key}}`, so changing
|
|
524
|
+
* either is a delete and a create. */
|
|
525
|
+
fallbackValue: string | null;
|
|
526
|
+
}
|
|
527
|
+
interface DeleteContactPropertyResponse {
|
|
528
|
+
deleted: true;
|
|
529
|
+
/** How many contacts had the key stripped from them. */
|
|
530
|
+
contactsUpdated: number;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* The organization's custom contact properties — the schema behind the `properties` bag
|
|
534
|
+
* each contact carries.
|
|
535
|
+
*
|
|
536
|
+
* Declaring a property is optional. A property arriving on a contact write that has never
|
|
537
|
+
* been declared registers itself as a `string`, so an existing integration needs no
|
|
538
|
+
* changes. Declaring one up front is what buys a type check and a fallback value.
|
|
539
|
+
*/
|
|
540
|
+
declare class ContactProperties {
|
|
541
|
+
private readonly client;
|
|
542
|
+
constructor(client: Eusend);
|
|
543
|
+
create(options: CreateContactPropertyOptions): Promise<EusendResponse<ContactProperty>>;
|
|
544
|
+
/** Every property the organization has defined. Unpaginated — the registry is capped at
|
|
545
|
+
* 100 entries, and a variable picker wants all of them. */
|
|
546
|
+
list(): Promise<EusendResponse<ContactProperty[]>>;
|
|
547
|
+
get(id: string): Promise<EusendResponse<ContactProperty>>;
|
|
548
|
+
update(id: string, options: UpdateContactPropertyOptions): Promise<EusendResponse<ContactProperty>>;
|
|
549
|
+
/**
|
|
550
|
+
* Delete a property definition AND strip the key from every contact in the organization.
|
|
551
|
+
*
|
|
552
|
+
* Destructive and not undoable. Leaving the values in place was the alternative, and a
|
|
553
|
+
* worse one: the property would keep rendering in broadcasts, and the next contact write
|
|
554
|
+
* carrying that key would register it again.
|
|
555
|
+
*/
|
|
556
|
+
delete(id: string): Promise<EusendResponse<DeleteContactPropertyResponse>>;
|
|
557
|
+
}
|
|
558
|
+
//#endregion
|
|
559
|
+
//#region src/topics.d.ts
|
|
560
|
+
/** What a contact who has never expressed a preference receives. Fixed at creation. */
|
|
561
|
+
type TopicDefaultSubscription = 'opt_in' | 'opt_out';
|
|
562
|
+
/** Whether the topic is listed on the unsubscribe page to a contact who is not opted in. */
|
|
563
|
+
type TopicVisibility = 'public' | 'private';
|
|
564
|
+
interface Topic {
|
|
565
|
+
id: string;
|
|
566
|
+
name: string;
|
|
567
|
+
description: string | null;
|
|
568
|
+
defaultSubscription: TopicDefaultSubscription;
|
|
569
|
+
visibility: TopicVisibility;
|
|
570
|
+
/** Contacts who explicitly opted in. Present on list and create, not on get. */
|
|
571
|
+
subscriberCount?: number;
|
|
572
|
+
createdAt: string;
|
|
573
|
+
updatedAt: string;
|
|
574
|
+
}
|
|
575
|
+
interface CreateTopicOptions {
|
|
576
|
+
name: string;
|
|
577
|
+
/** `opt_in` reaches everyone until they leave; `opt_out` reaches nobody until they join.
|
|
578
|
+
* Cannot be changed afterwards. */
|
|
579
|
+
defaultSubscription: TopicDefaultSubscription;
|
|
580
|
+
description?: string | null;
|
|
581
|
+
/** Defaults to `private`. */
|
|
582
|
+
visibility?: TopicVisibility;
|
|
583
|
+
}
|
|
584
|
+
/** `defaultSubscription` is absent deliberately — it is fixed at creation. */
|
|
585
|
+
interface UpdateTopicOptions {
|
|
586
|
+
name?: string;
|
|
587
|
+
description?: string | null;
|
|
588
|
+
visibility?: TopicVisibility;
|
|
589
|
+
}
|
|
590
|
+
interface DeleteTopicResponse {
|
|
591
|
+
id: string;
|
|
592
|
+
deleted: true;
|
|
593
|
+
}
|
|
594
|
+
interface TopicSubscriptionResponse {
|
|
595
|
+
topicId: string;
|
|
596
|
+
contactId: string;
|
|
597
|
+
subscribed: boolean;
|
|
598
|
+
}
|
|
599
|
+
interface ClearTopicSubscriptionResponse {
|
|
600
|
+
topicId: string;
|
|
601
|
+
contactId: string;
|
|
602
|
+
deleted: true;
|
|
603
|
+
}
|
|
604
|
+
declare class Topics {
|
|
605
|
+
private readonly client;
|
|
606
|
+
constructor(client: Eusend);
|
|
607
|
+
create(options: CreateTopicOptions): Promise<EusendResponse<Topic>>;
|
|
608
|
+
/** Every topic the organization has defined. Unpaginated — the list is capped at 100,
|
|
609
|
+
* and both the composer's picker and the unsubscribe page want all of it. */
|
|
610
|
+
list(): Promise<EusendResponse<Topic[]>>;
|
|
611
|
+
get(id: string): Promise<EusendResponse<Topic>>;
|
|
612
|
+
update(id: string, options: UpdateTopicOptions): Promise<EusendResponse<Topic>>;
|
|
613
|
+
/** Deletes the topic and every stored preference for it. A draft or scheduled broadcast
|
|
614
|
+
* scoped to it widens back to its whole audience. */
|
|
615
|
+
delete(id: string): Promise<EusendResponse<DeleteTopicResponse>>;
|
|
616
|
+
/** Record an explicit preference for one contact. */
|
|
617
|
+
subscribe(topicId: string, contactId: string, subscribed?: boolean): Promise<EusendResponse<TopicSubscriptionResponse>>;
|
|
618
|
+
/**
|
|
619
|
+
* Forget the contact's explicit choice, so they fall back to the topic's default.
|
|
620
|
+
*
|
|
621
|
+
* Different from `subscribe(id, contactId, false)`: that records "no thanks", this
|
|
622
|
+
* records nothing at all — so on an opt-in topic the contact starts receiving it again.
|
|
623
|
+
*/
|
|
624
|
+
clearSubscription(topicId: string, contactId: string): Promise<EusendResponse<ClearTopicSubscriptionResponse>>;
|
|
625
|
+
}
|
|
626
|
+
//#endregion
|
|
496
627
|
//#region src/templates.d.ts
|
|
497
628
|
interface TemplateHtmlOrReact {
|
|
498
629
|
/**
|
|
@@ -591,6 +722,9 @@ type BroadcastStatus = 'draft' | 'scheduled' | 'sending' | 'sent' | 'paused' | '
|
|
|
591
722
|
interface CreateBroadcastOptions {
|
|
592
723
|
name: string;
|
|
593
724
|
audienceId: string;
|
|
725
|
+
/** Narrows the audience to the contacts subscribed to this topic. Omit to send to all
|
|
726
|
+
* of it. */
|
|
727
|
+
topicId?: string;
|
|
594
728
|
/**
|
|
595
729
|
* Sender address. Accepts a bare email (`onboarding@eusend.dev`) or a display-name
|
|
596
730
|
* form (`Acme <onboarding@eusend.dev>`). The domain must be verified on your account.
|
|
@@ -620,6 +754,8 @@ interface CreateBroadcastOptions {
|
|
|
620
754
|
interface UpdateBroadcastOptions {
|
|
621
755
|
name?: string;
|
|
622
756
|
audienceId?: string;
|
|
757
|
+
/** Pass null to clear the topic and widen the send back to the whole audience. */
|
|
758
|
+
topicId?: string | null;
|
|
623
759
|
from?: string;
|
|
624
760
|
subject?: string;
|
|
625
761
|
html?: string;
|
|
@@ -651,6 +787,8 @@ interface Broadcast {
|
|
|
651
787
|
status: BroadcastStatus;
|
|
652
788
|
/** Null when the associated audience has been deleted. */
|
|
653
789
|
audienceId: string | null;
|
|
790
|
+
/** The topic this broadcast is scoped to, or null for the whole audience. */
|
|
791
|
+
topicId: string | null;
|
|
654
792
|
fromAddress: string;
|
|
655
793
|
replyTo: string | null;
|
|
656
794
|
subject: string;
|
|
@@ -676,6 +814,8 @@ interface BroadcastListItem {
|
|
|
676
814
|
status: BroadcastStatus;
|
|
677
815
|
/** Null when the associated audience has been deleted. */
|
|
678
816
|
audienceId: string | null;
|
|
817
|
+
topicId: string | null;
|
|
818
|
+
topicName: string | null;
|
|
679
819
|
fromAddress: string;
|
|
680
820
|
subject: string;
|
|
681
821
|
recipientCount: number | null;
|
|
@@ -819,6 +959,10 @@ declare class Eusend {
|
|
|
819
959
|
readonly domains: Domains;
|
|
820
960
|
readonly apiKeys: ApiKeys;
|
|
821
961
|
readonly audiences: Audiences;
|
|
962
|
+
/** The org's declared contact properties — `client.contactProperties.list()`. */
|
|
963
|
+
readonly contactProperties: ContactProperties;
|
|
964
|
+
/** Subscription topics — `client.topics.list()`. */
|
|
965
|
+
readonly topics: Topics;
|
|
822
966
|
readonly templates: Templates;
|
|
823
967
|
readonly webhooks: Webhooks;
|
|
824
968
|
readonly broadcasts: Broadcasts;
|
|
@@ -828,8 +972,9 @@ declare class Eusend {
|
|
|
828
972
|
get<T>(path: string, extraHeaders?: Record<string, string>): Promise<EusendResponse<T>>;
|
|
829
973
|
post<T>(path: string, body?: unknown, extraHeaders?: Record<string, string>): Promise<EusendResponse<T>>;
|
|
830
974
|
patch<T>(path: string, body?: unknown): Promise<EusendResponse<T>>;
|
|
975
|
+
put<T>(path: string, body?: unknown): Promise<EusendResponse<T>>;
|
|
831
976
|
delete<T>(path: string): Promise<EusendResponse<T>>;
|
|
832
977
|
}
|
|
833
978
|
//#endregion
|
|
834
|
-
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 Contact, type ContactStatus, type CreateApiKeyOptions, type CreateApiKeyResponse, type CreateBroadcastOptions, type CreateContactOptions, type CreateDomainResponse, type CreateSuppressionOptions, type CreateTemplateOptions, type CreateWebhookOptions, type CreateWebhookResponse, 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 UpdateBroadcastOptions, type UpdateContactOptions, type UpdateEmailOptions, type UpdateEmailResponse, type UpdateTemplateOptions, type UpdateWebhookOptions, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookWithDeliveries };
|
|
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 };
|
|
835
980
|
//# 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/templates.ts","../src/webhooks.ts","../src/broadcasts.ts","../src/suppressions.ts","../src/eusend.ts"],"mappings":"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
|
|
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
|
@@ -274,6 +274,109 @@ var Audiences = class {
|
|
|
274
274
|
}
|
|
275
275
|
};
|
|
276
276
|
//#endregion
|
|
277
|
+
//#region src/contact-properties.ts
|
|
278
|
+
/**
|
|
279
|
+
* The organization's custom contact properties — the schema behind the `properties` bag
|
|
280
|
+
* each contact carries.
|
|
281
|
+
*
|
|
282
|
+
* Declaring a property is optional. A property arriving on a contact write that has never
|
|
283
|
+
* been declared registers itself as a `string`, so an existing integration needs no
|
|
284
|
+
* changes. Declaring one up front is what buys a type check and a fallback value.
|
|
285
|
+
*/
|
|
286
|
+
var ContactProperties = class {
|
|
287
|
+
constructor(client) {
|
|
288
|
+
this.client = client;
|
|
289
|
+
}
|
|
290
|
+
create(options) {
|
|
291
|
+
return this.client.post("/contact-properties", {
|
|
292
|
+
key: options.key,
|
|
293
|
+
type: options.type,
|
|
294
|
+
fallback_value: options.fallbackValue
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
/** Every property the organization has defined. Unpaginated — the registry is capped at
|
|
298
|
+
* 100 entries, and a variable picker wants all of them. */
|
|
299
|
+
async list() {
|
|
300
|
+
const res = await this.client.get("/contact-properties");
|
|
301
|
+
if (res.error) return res;
|
|
302
|
+
return {
|
|
303
|
+
data: res.data.data,
|
|
304
|
+
error: null,
|
|
305
|
+
headers: res.headers
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
get(id) {
|
|
309
|
+
return this.client.get(`/contact-properties/${id}`);
|
|
310
|
+
}
|
|
311
|
+
update(id, options) {
|
|
312
|
+
return this.client.patch(`/contact-properties/${id}`, { fallback_value: options.fallbackValue });
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Delete a property definition AND strip the key from every contact in the organization.
|
|
316
|
+
*
|
|
317
|
+
* Destructive and not undoable. Leaving the values in place was the alternative, and a
|
|
318
|
+
* worse one: the property would keep rendering in broadcasts, and the next contact write
|
|
319
|
+
* carrying that key would register it again.
|
|
320
|
+
*/
|
|
321
|
+
delete(id) {
|
|
322
|
+
return this.client.delete(`/contact-properties/${id}`);
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
//#endregion
|
|
326
|
+
//#region src/topics.ts
|
|
327
|
+
var Topics = class {
|
|
328
|
+
constructor(client) {
|
|
329
|
+
this.client = client;
|
|
330
|
+
}
|
|
331
|
+
create(options) {
|
|
332
|
+
return this.client.post("/topics", {
|
|
333
|
+
name: options.name,
|
|
334
|
+
default_subscription: options.defaultSubscription,
|
|
335
|
+
description: options.description,
|
|
336
|
+
visibility: options.visibility
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
/** Every topic the organization has defined. Unpaginated — the list is capped at 100,
|
|
340
|
+
* and both the composer's picker and the unsubscribe page want all of it. */
|
|
341
|
+
async list() {
|
|
342
|
+
const res = await this.client.get("/topics");
|
|
343
|
+
if (res.error) return res;
|
|
344
|
+
return {
|
|
345
|
+
data: res.data.data,
|
|
346
|
+
error: null,
|
|
347
|
+
headers: res.headers
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
get(id) {
|
|
351
|
+
return this.client.get(`/topics/${id}`);
|
|
352
|
+
}
|
|
353
|
+
update(id, options) {
|
|
354
|
+
return this.client.patch(`/topics/${id}`, {
|
|
355
|
+
name: options.name,
|
|
356
|
+
description: options.description,
|
|
357
|
+
visibility: options.visibility
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
/** Deletes the topic and every stored preference for it. A draft or scheduled broadcast
|
|
361
|
+
* scoped to it widens back to its whole audience. */
|
|
362
|
+
delete(id) {
|
|
363
|
+
return this.client.delete(`/topics/${id}`);
|
|
364
|
+
}
|
|
365
|
+
/** Record an explicit preference for one contact. */
|
|
366
|
+
subscribe(topicId, contactId, subscribed = true) {
|
|
367
|
+
return this.client.put(`/topics/${topicId}/contacts/${contactId}`, { subscribed });
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Forget the contact's explicit choice, so they fall back to the topic's default.
|
|
371
|
+
*
|
|
372
|
+
* Different from `subscribe(id, contactId, false)`: that records "no thanks", this
|
|
373
|
+
* records nothing at all — so on an opt-in topic the contact starts receiving it again.
|
|
374
|
+
*/
|
|
375
|
+
clearSubscription(topicId, contactId) {
|
|
376
|
+
return this.client.delete(`/topics/${topicId}/contacts/${contactId}`);
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
//#endregion
|
|
277
380
|
//#region src/templates.ts
|
|
278
381
|
async function resolveTemplateHtml(options) {
|
|
279
382
|
if (options.html) return options.html;
|
|
@@ -373,6 +476,7 @@ var Broadcasts = class {
|
|
|
373
476
|
return this.client.post("/broadcasts", {
|
|
374
477
|
name: options.name,
|
|
375
478
|
audience_id: options.audienceId,
|
|
479
|
+
topic_id: options.topicId,
|
|
376
480
|
from: options.from,
|
|
377
481
|
subject: options.subject,
|
|
378
482
|
html,
|
|
@@ -399,6 +503,7 @@ var Broadcasts = class {
|
|
|
399
503
|
return this.client.patch(`/broadcasts/${id}`, {
|
|
400
504
|
name: options.name,
|
|
401
505
|
audience_id: options.audienceId,
|
|
506
|
+
topic_id: options.topicId,
|
|
402
507
|
from: options.from,
|
|
403
508
|
subject: options.subject,
|
|
404
509
|
html,
|
|
@@ -510,7 +615,7 @@ var Suppressions = class {
|
|
|
510
615
|
//#endregion
|
|
511
616
|
//#region src/eusend.ts
|
|
512
617
|
const DEFAULT_BASE_URL = "https://api.eusend.dev";
|
|
513
|
-
const SDK_VERSION = "0.
|
|
618
|
+
const SDK_VERSION = "0.17.0";
|
|
514
619
|
var Eusend = class {
|
|
515
620
|
constructor(key, options) {
|
|
516
621
|
const apiKey = key ?? (typeof process !== "undefined" ? process.env["EUSEND_API_KEY"] : void 0);
|
|
@@ -522,6 +627,8 @@ var Eusend = class {
|
|
|
522
627
|
this.domains = new Domains(this);
|
|
523
628
|
this.apiKeys = new ApiKeys(this);
|
|
524
629
|
this.audiences = new Audiences(this);
|
|
630
|
+
this.contactProperties = new ContactProperties(this);
|
|
631
|
+
this.topics = new Topics(this);
|
|
525
632
|
this.templates = new Templates(this);
|
|
526
633
|
this.webhooks = new Webhooks(this);
|
|
527
634
|
this.broadcasts = new Broadcasts(this);
|
|
@@ -599,6 +706,12 @@ var Eusend = class {
|
|
|
599
706
|
body: body != null ? JSON.stringify(body) : void 0
|
|
600
707
|
});
|
|
601
708
|
}
|
|
709
|
+
put(path, body) {
|
|
710
|
+
return this.fetchRequest(path, {
|
|
711
|
+
method: "PUT",
|
|
712
|
+
body: body != null ? JSON.stringify(body) : void 0
|
|
713
|
+
});
|
|
714
|
+
}
|
|
602
715
|
delete(path) {
|
|
603
716
|
return this.fetchRequest(path, { method: "DELETE" });
|
|
604
717
|
}
|
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/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'\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 /**\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 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 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 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 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 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 { 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.15.1'\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 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.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 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 /** 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.17.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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"}
|