@masters-union/outbound-sdk 0.4.6 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +49 -12
- package/dist/index.d.ts +49 -12
- package/dist/index.js +0 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +0 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -51,7 +51,7 @@ interface BulkEmailParams {
|
|
|
51
51
|
* Inline recipients, up to 1000 per request. Mutually exclusive with `listId`.
|
|
52
52
|
* Required unless `listId` is given.
|
|
53
53
|
*/
|
|
54
|
-
emails?: BulkEmailRecipient
|
|
54
|
+
emails?: Array<BulkEmailRecipient | BulkEmailMergeRecipient>;
|
|
55
55
|
/**
|
|
56
56
|
* Send to a saved contact list instead. NO RECIPIENT CAP: the server expands the
|
|
57
57
|
* list in the background and returns one job id to track. `htmlBody` is required
|
|
@@ -91,11 +91,17 @@ interface BulkEmailParams {
|
|
|
91
91
|
}
|
|
92
92
|
interface BulkEmailRecipient {
|
|
93
93
|
toEmail: string;
|
|
94
|
-
/** Required unless a shared top-level `htmlBody` is supplied. */
|
|
95
|
-
htmlBody?: string;
|
|
96
94
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
95
|
+
* This recipient's own HTML body. Still REQUIRED on this shape, deliberately —
|
|
96
|
+
* making it optional would turn `recipient.htmlBody.length` into a compile error
|
|
97
|
+
* for anyone who upgraded. To omit it, use the mail-merge shape
|
|
98
|
+
* `BulkEmailMergeRecipient` instead, which the `emails` array also accepts.
|
|
99
|
+
*/
|
|
100
|
+
htmlBody: string;
|
|
101
|
+
/**
|
|
102
|
+
* Optional mail-merge values. Its PRESENCE is what opts this entry into
|
|
103
|
+
* server-side rendering, so omit it entirely for a body sent verbatim — even one
|
|
104
|
+
* containing a literal `{{...}}`.
|
|
99
105
|
*/
|
|
100
106
|
variables?: Record<string, string>;
|
|
101
107
|
subject?: string;
|
|
@@ -105,6 +111,25 @@ interface BulkEmailRecipient {
|
|
|
105
111
|
metadata?: Record<string, unknown>;
|
|
106
112
|
attachments?: Attachment[];
|
|
107
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* A mail-merge recipient: no body of its own, because the request carries a shared
|
|
116
|
+
* `htmlBody` that is rendered per recipient from `variables`.
|
|
117
|
+
*
|
|
118
|
+
* A SEPARATE interface rather than loosening `BulkEmailRecipient.htmlBody`, so that
|
|
119
|
+
* adding mail merge cannot break a single existing consumer's build.
|
|
120
|
+
*/
|
|
121
|
+
interface BulkEmailMergeRecipient {
|
|
122
|
+
toEmail: string;
|
|
123
|
+
variables?: Record<string, string>;
|
|
124
|
+
/** Overrides the shared body for just this recipient. */
|
|
125
|
+
htmlBody?: string;
|
|
126
|
+
subject?: string;
|
|
127
|
+
textBody?: string;
|
|
128
|
+
ccEmail?: string;
|
|
129
|
+
bccEmail?: string;
|
|
130
|
+
metadata?: Record<string, unknown>;
|
|
131
|
+
attachments?: Attachment[];
|
|
132
|
+
}
|
|
108
133
|
interface BulkEmailResponse {
|
|
109
134
|
message?: string;
|
|
110
135
|
jobId: string | null;
|
|
@@ -1060,11 +1085,17 @@ declare class EmailResource {
|
|
|
1060
1085
|
* - `emails[]` with a full `htmlBody` each — the original behaviour, unchanged.
|
|
1061
1086
|
* - `emails[]` + a shared `htmlBody` + per-recipient `variables` — MAIL MERGE.
|
|
1062
1087
|
* The template crosses the wire once instead of once per recipient.
|
|
1063
|
-
* - `listId` (+ `mapping`) — a saved contact list, with NO recipient cap.
|
|
1064
|
-
*
|
|
1065
|
-
*
|
|
1088
|
+
* - `listId` (+ `mapping`) — a saved contact list, with NO recipient cap. The
|
|
1089
|
+
* server materializes the recipients in the background and returns a job id.
|
|
1090
|
+
*
|
|
1091
|
+
* OVERLOADED rather than returning a union, so existing calls keep resolving to
|
|
1092
|
+
* `BulkEmailResponse` exactly as before. A bare union would have made
|
|
1093
|
+
* `res.recipientCount` a compile error for every caller that upgraded.
|
|
1066
1094
|
*/
|
|
1067
|
-
bulk(params: BulkEmailParams
|
|
1095
|
+
bulk(params: BulkEmailParams & {
|
|
1096
|
+
listId: string;
|
|
1097
|
+
}, overrides?: RequestOverrides): Promise<ListSendResponse>;
|
|
1098
|
+
bulk(params: BulkEmailParams, overrides?: RequestOverrides): Promise<BulkEmailResponse>;
|
|
1068
1099
|
status(jobId: string, overrides?: RequestOverrides): Promise<JobStatusResponse>;
|
|
1069
1100
|
/**
|
|
1070
1101
|
* Look up the current status of a single message by its `messageId` — the ID
|
|
@@ -1118,9 +1149,15 @@ declare class TemplatesResource {
|
|
|
1118
1149
|
*
|
|
1119
1150
|
* Pass `recipients[]` (up to 1000) for an inline send, or `listId` (+ `mapping`)
|
|
1120
1151
|
* to send to a whole saved contact list with no recipient cap — the server
|
|
1121
|
-
* expands the list in the background
|
|
1152
|
+
* expands the list in the background.
|
|
1153
|
+
*
|
|
1154
|
+
* Overloaded rather than returning a union, so existing calls keep resolving to
|
|
1155
|
+
* `TemplateBulkSendResponse` and upgrading the SDK cannot break a build.
|
|
1122
1156
|
*/
|
|
1123
|
-
bulkSend(params: TemplateBulkSendParams
|
|
1157
|
+
bulkSend(params: TemplateBulkSendParams & {
|
|
1158
|
+
listId: string;
|
|
1159
|
+
}, overrides?: RequestOverrides): Promise<ListSendResponse>;
|
|
1160
|
+
bulkSend(params: TemplateBulkSendParams, overrides?: RequestOverrides): Promise<TemplateBulkSendResponse>;
|
|
1124
1161
|
stats(overrides?: RequestOverrides): Promise<TemplateStatsResponse>;
|
|
1125
1162
|
}
|
|
1126
1163
|
|
|
@@ -1355,4 +1392,4 @@ declare class NetworkError extends OutboundError {
|
|
|
1355
1392
|
constructor(message?: string);
|
|
1356
1393
|
}
|
|
1357
1394
|
|
|
1358
|
-
export { type AcceptedResponse, type AddContactParams, type AddSuppressionParams, type AnyIncomingWebhookPayload, type Attachment, AuthenticationError, BadRequestError, type BulkAddSuppressionsParams, type BulkAddSuppressionsResponse, type BulkDeleteContactsParams, type BulkDeleteContactsResponse, type BulkEmailParams, type BulkEmailRecipient, type BulkEmailResponse, type BulkRemoveSuppressionsParams, type BulkRemoveSuppressionsResponse, type BulkResponseRecipient, type CampaignAnalytics, type CampaignAnalyticsParams, type CampaignBounceReason, type CampaignDomainStat, type CampaignRates, type CampaignStatus, type CampaignSummary, type CampaignTimeseriesPoint, type CampaignTotals, type CancelEmailParams, type CancelEmailResponse, type CheckQuotaResponse, ConflictError, type Contact, type ContactList, type ContactListDetail, type ContactListFieldsResponse, type ContactStatus, type ContactStatusReason, type CreateContactListParams, type CreateTemplateParams, type CreateWebhookParams, type CreateWebhookResponse, type DashboardResponse, type DedicatedIpWarmup, type EmailJob, type EmailList, type EmailRecipientStatus, type EmailStatus, ForbiddenError, type GlobalQuotaResponse, type ImportContactRow, type ImportContactsParams, type ImportContactsResponse, type IncomingWebhookEvent, type IncomingWebhookEventV2, type IncomingWebhookPayload, type IncomingWebhookPayloadV2, type IpPoolStatus, type JobStatusResponse, type ListCampaignsParams, type ListCampaignsResponse, type ListContactListsParams, type ListContactListsResponse, type ListContactsParams, type ListContactsResponse, type ListSendResponse, type ListSuppressionsParams, type ListSuppressionsResponse, type ListTemplatesParams, type ListTemplatesResponse, type ListWebhooksResponse, type MessageContentResponse, type MessageStatusRecipient, type MessageStatusResponse, NetworkError, NotFoundError, Outbound, type OutboundConfig, OutboundError, type QuotaResponse, RateLimitError, type RecountContactListResponse, type RejectedEmail, type RequestOverrides, type ResolvedConfig, type SearchSuppressionsParams, type SearchSuppressionsResponse, type SendEmailParams, type SendEmailResponse, ServerError, type Suppression, type SuppressionReason, type SuppressionResponse, type Template, type TemplateBulkRecipient, type TemplateBulkSendParams, type TemplateBulkSendResponse, type TemplatePreviewParams, type TemplatePreviewResponse, type TemplateResponse, type TemplateSendParams, type TemplateStatsResponse, TimeoutError, type UpdateContactListParams, type UpdateContactParams, type UpdateTemplateParams, type UpdateWebhookParams, type UpdateWebhookResponse, type VariableMapping, type Webhook, type WebhookEvent, type WebhookEventDetails, type WebhookEventStatus, type WebhookRetryStrategy };
|
|
1395
|
+
export { type AcceptedResponse, type AddContactParams, type AddSuppressionParams, type AnyIncomingWebhookPayload, type Attachment, AuthenticationError, BadRequestError, type BulkAddSuppressionsParams, type BulkAddSuppressionsResponse, type BulkDeleteContactsParams, type BulkDeleteContactsResponse, type BulkEmailMergeRecipient, type BulkEmailParams, type BulkEmailRecipient, type BulkEmailResponse, type BulkRemoveSuppressionsParams, type BulkRemoveSuppressionsResponse, type BulkResponseRecipient, type CampaignAnalytics, type CampaignAnalyticsParams, type CampaignBounceReason, type CampaignDomainStat, type CampaignRates, type CampaignStatus, type CampaignSummary, type CampaignTimeseriesPoint, type CampaignTotals, type CancelEmailParams, type CancelEmailResponse, type CheckQuotaResponse, ConflictError, type Contact, type ContactList, type ContactListDetail, type ContactListFieldsResponse, type ContactStatus, type ContactStatusReason, type CreateContactListParams, type CreateTemplateParams, type CreateWebhookParams, type CreateWebhookResponse, type DashboardResponse, type DedicatedIpWarmup, type EmailJob, type EmailList, type EmailRecipientStatus, type EmailStatus, ForbiddenError, type GlobalQuotaResponse, type ImportContactRow, type ImportContactsParams, type ImportContactsResponse, type IncomingWebhookEvent, type IncomingWebhookEventV2, type IncomingWebhookPayload, type IncomingWebhookPayloadV2, type IpPoolStatus, type JobStatusResponse, type ListCampaignsParams, type ListCampaignsResponse, type ListContactListsParams, type ListContactListsResponse, type ListContactsParams, type ListContactsResponse, type ListSendResponse, type ListSuppressionsParams, type ListSuppressionsResponse, type ListTemplatesParams, type ListTemplatesResponse, type ListWebhooksResponse, type MessageContentResponse, type MessageStatusRecipient, type MessageStatusResponse, NetworkError, NotFoundError, Outbound, type OutboundConfig, OutboundError, type QuotaResponse, RateLimitError, type RecountContactListResponse, type RejectedEmail, type RequestOverrides, type ResolvedConfig, type SearchSuppressionsParams, type SearchSuppressionsResponse, type SendEmailParams, type SendEmailResponse, ServerError, type Suppression, type SuppressionReason, type SuppressionResponse, type Template, type TemplateBulkRecipient, type TemplateBulkSendParams, type TemplateBulkSendResponse, type TemplatePreviewParams, type TemplatePreviewResponse, type TemplateResponse, type TemplateSendParams, type TemplateStatsResponse, TimeoutError, type UpdateContactListParams, type UpdateContactParams, type UpdateTemplateParams, type UpdateWebhookParams, type UpdateWebhookResponse, type VariableMapping, type Webhook, type WebhookEvent, type WebhookEventDetails, type WebhookEventStatus, type WebhookRetryStrategy };
|
package/dist/index.d.ts
CHANGED
|
@@ -51,7 +51,7 @@ interface BulkEmailParams {
|
|
|
51
51
|
* Inline recipients, up to 1000 per request. Mutually exclusive with `listId`.
|
|
52
52
|
* Required unless `listId` is given.
|
|
53
53
|
*/
|
|
54
|
-
emails?: BulkEmailRecipient
|
|
54
|
+
emails?: Array<BulkEmailRecipient | BulkEmailMergeRecipient>;
|
|
55
55
|
/**
|
|
56
56
|
* Send to a saved contact list instead. NO RECIPIENT CAP: the server expands the
|
|
57
57
|
* list in the background and returns one job id to track. `htmlBody` is required
|
|
@@ -91,11 +91,17 @@ interface BulkEmailParams {
|
|
|
91
91
|
}
|
|
92
92
|
interface BulkEmailRecipient {
|
|
93
93
|
toEmail: string;
|
|
94
|
-
/** Required unless a shared top-level `htmlBody` is supplied. */
|
|
95
|
-
htmlBody?: string;
|
|
96
94
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
95
|
+
* This recipient's own HTML body. Still REQUIRED on this shape, deliberately —
|
|
96
|
+
* making it optional would turn `recipient.htmlBody.length` into a compile error
|
|
97
|
+
* for anyone who upgraded. To omit it, use the mail-merge shape
|
|
98
|
+
* `BulkEmailMergeRecipient` instead, which the `emails` array also accepts.
|
|
99
|
+
*/
|
|
100
|
+
htmlBody: string;
|
|
101
|
+
/**
|
|
102
|
+
* Optional mail-merge values. Its PRESENCE is what opts this entry into
|
|
103
|
+
* server-side rendering, so omit it entirely for a body sent verbatim — even one
|
|
104
|
+
* containing a literal `{{...}}`.
|
|
99
105
|
*/
|
|
100
106
|
variables?: Record<string, string>;
|
|
101
107
|
subject?: string;
|
|
@@ -105,6 +111,25 @@ interface BulkEmailRecipient {
|
|
|
105
111
|
metadata?: Record<string, unknown>;
|
|
106
112
|
attachments?: Attachment[];
|
|
107
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* A mail-merge recipient: no body of its own, because the request carries a shared
|
|
116
|
+
* `htmlBody` that is rendered per recipient from `variables`.
|
|
117
|
+
*
|
|
118
|
+
* A SEPARATE interface rather than loosening `BulkEmailRecipient.htmlBody`, so that
|
|
119
|
+
* adding mail merge cannot break a single existing consumer's build.
|
|
120
|
+
*/
|
|
121
|
+
interface BulkEmailMergeRecipient {
|
|
122
|
+
toEmail: string;
|
|
123
|
+
variables?: Record<string, string>;
|
|
124
|
+
/** Overrides the shared body for just this recipient. */
|
|
125
|
+
htmlBody?: string;
|
|
126
|
+
subject?: string;
|
|
127
|
+
textBody?: string;
|
|
128
|
+
ccEmail?: string;
|
|
129
|
+
bccEmail?: string;
|
|
130
|
+
metadata?: Record<string, unknown>;
|
|
131
|
+
attachments?: Attachment[];
|
|
132
|
+
}
|
|
108
133
|
interface BulkEmailResponse {
|
|
109
134
|
message?: string;
|
|
110
135
|
jobId: string | null;
|
|
@@ -1060,11 +1085,17 @@ declare class EmailResource {
|
|
|
1060
1085
|
* - `emails[]` with a full `htmlBody` each — the original behaviour, unchanged.
|
|
1061
1086
|
* - `emails[]` + a shared `htmlBody` + per-recipient `variables` — MAIL MERGE.
|
|
1062
1087
|
* The template crosses the wire once instead of once per recipient.
|
|
1063
|
-
* - `listId` (+ `mapping`) — a saved contact list, with NO recipient cap.
|
|
1064
|
-
*
|
|
1065
|
-
*
|
|
1088
|
+
* - `listId` (+ `mapping`) — a saved contact list, with NO recipient cap. The
|
|
1089
|
+
* server materializes the recipients in the background and returns a job id.
|
|
1090
|
+
*
|
|
1091
|
+
* OVERLOADED rather than returning a union, so existing calls keep resolving to
|
|
1092
|
+
* `BulkEmailResponse` exactly as before. A bare union would have made
|
|
1093
|
+
* `res.recipientCount` a compile error for every caller that upgraded.
|
|
1066
1094
|
*/
|
|
1067
|
-
bulk(params: BulkEmailParams
|
|
1095
|
+
bulk(params: BulkEmailParams & {
|
|
1096
|
+
listId: string;
|
|
1097
|
+
}, overrides?: RequestOverrides): Promise<ListSendResponse>;
|
|
1098
|
+
bulk(params: BulkEmailParams, overrides?: RequestOverrides): Promise<BulkEmailResponse>;
|
|
1068
1099
|
status(jobId: string, overrides?: RequestOverrides): Promise<JobStatusResponse>;
|
|
1069
1100
|
/**
|
|
1070
1101
|
* Look up the current status of a single message by its `messageId` — the ID
|
|
@@ -1118,9 +1149,15 @@ declare class TemplatesResource {
|
|
|
1118
1149
|
*
|
|
1119
1150
|
* Pass `recipients[]` (up to 1000) for an inline send, or `listId` (+ `mapping`)
|
|
1120
1151
|
* to send to a whole saved contact list with no recipient cap — the server
|
|
1121
|
-
* expands the list in the background
|
|
1152
|
+
* expands the list in the background.
|
|
1153
|
+
*
|
|
1154
|
+
* Overloaded rather than returning a union, so existing calls keep resolving to
|
|
1155
|
+
* `TemplateBulkSendResponse` and upgrading the SDK cannot break a build.
|
|
1122
1156
|
*/
|
|
1123
|
-
bulkSend(params: TemplateBulkSendParams
|
|
1157
|
+
bulkSend(params: TemplateBulkSendParams & {
|
|
1158
|
+
listId: string;
|
|
1159
|
+
}, overrides?: RequestOverrides): Promise<ListSendResponse>;
|
|
1160
|
+
bulkSend(params: TemplateBulkSendParams, overrides?: RequestOverrides): Promise<TemplateBulkSendResponse>;
|
|
1124
1161
|
stats(overrides?: RequestOverrides): Promise<TemplateStatsResponse>;
|
|
1125
1162
|
}
|
|
1126
1163
|
|
|
@@ -1355,4 +1392,4 @@ declare class NetworkError extends OutboundError {
|
|
|
1355
1392
|
constructor(message?: string);
|
|
1356
1393
|
}
|
|
1357
1394
|
|
|
1358
|
-
export { type AcceptedResponse, type AddContactParams, type AddSuppressionParams, type AnyIncomingWebhookPayload, type Attachment, AuthenticationError, BadRequestError, type BulkAddSuppressionsParams, type BulkAddSuppressionsResponse, type BulkDeleteContactsParams, type BulkDeleteContactsResponse, type BulkEmailParams, type BulkEmailRecipient, type BulkEmailResponse, type BulkRemoveSuppressionsParams, type BulkRemoveSuppressionsResponse, type BulkResponseRecipient, type CampaignAnalytics, type CampaignAnalyticsParams, type CampaignBounceReason, type CampaignDomainStat, type CampaignRates, type CampaignStatus, type CampaignSummary, type CampaignTimeseriesPoint, type CampaignTotals, type CancelEmailParams, type CancelEmailResponse, type CheckQuotaResponse, ConflictError, type Contact, type ContactList, type ContactListDetail, type ContactListFieldsResponse, type ContactStatus, type ContactStatusReason, type CreateContactListParams, type CreateTemplateParams, type CreateWebhookParams, type CreateWebhookResponse, type DashboardResponse, type DedicatedIpWarmup, type EmailJob, type EmailList, type EmailRecipientStatus, type EmailStatus, ForbiddenError, type GlobalQuotaResponse, type ImportContactRow, type ImportContactsParams, type ImportContactsResponse, type IncomingWebhookEvent, type IncomingWebhookEventV2, type IncomingWebhookPayload, type IncomingWebhookPayloadV2, type IpPoolStatus, type JobStatusResponse, type ListCampaignsParams, type ListCampaignsResponse, type ListContactListsParams, type ListContactListsResponse, type ListContactsParams, type ListContactsResponse, type ListSendResponse, type ListSuppressionsParams, type ListSuppressionsResponse, type ListTemplatesParams, type ListTemplatesResponse, type ListWebhooksResponse, type MessageContentResponse, type MessageStatusRecipient, type MessageStatusResponse, NetworkError, NotFoundError, Outbound, type OutboundConfig, OutboundError, type QuotaResponse, RateLimitError, type RecountContactListResponse, type RejectedEmail, type RequestOverrides, type ResolvedConfig, type SearchSuppressionsParams, type SearchSuppressionsResponse, type SendEmailParams, type SendEmailResponse, ServerError, type Suppression, type SuppressionReason, type SuppressionResponse, type Template, type TemplateBulkRecipient, type TemplateBulkSendParams, type TemplateBulkSendResponse, type TemplatePreviewParams, type TemplatePreviewResponse, type TemplateResponse, type TemplateSendParams, type TemplateStatsResponse, TimeoutError, type UpdateContactListParams, type UpdateContactParams, type UpdateTemplateParams, type UpdateWebhookParams, type UpdateWebhookResponse, type VariableMapping, type Webhook, type WebhookEvent, type WebhookEventDetails, type WebhookEventStatus, type WebhookRetryStrategy };
|
|
1395
|
+
export { type AcceptedResponse, type AddContactParams, type AddSuppressionParams, type AnyIncomingWebhookPayload, type Attachment, AuthenticationError, BadRequestError, type BulkAddSuppressionsParams, type BulkAddSuppressionsResponse, type BulkDeleteContactsParams, type BulkDeleteContactsResponse, type BulkEmailMergeRecipient, type BulkEmailParams, type BulkEmailRecipient, type BulkEmailResponse, type BulkRemoveSuppressionsParams, type BulkRemoveSuppressionsResponse, type BulkResponseRecipient, type CampaignAnalytics, type CampaignAnalyticsParams, type CampaignBounceReason, type CampaignDomainStat, type CampaignRates, type CampaignStatus, type CampaignSummary, type CampaignTimeseriesPoint, type CampaignTotals, type CancelEmailParams, type CancelEmailResponse, type CheckQuotaResponse, ConflictError, type Contact, type ContactList, type ContactListDetail, type ContactListFieldsResponse, type ContactStatus, type ContactStatusReason, type CreateContactListParams, type CreateTemplateParams, type CreateWebhookParams, type CreateWebhookResponse, type DashboardResponse, type DedicatedIpWarmup, type EmailJob, type EmailList, type EmailRecipientStatus, type EmailStatus, ForbiddenError, type GlobalQuotaResponse, type ImportContactRow, type ImportContactsParams, type ImportContactsResponse, type IncomingWebhookEvent, type IncomingWebhookEventV2, type IncomingWebhookPayload, type IncomingWebhookPayloadV2, type IpPoolStatus, type JobStatusResponse, type ListCampaignsParams, type ListCampaignsResponse, type ListContactListsParams, type ListContactListsResponse, type ListContactsParams, type ListContactsResponse, type ListSendResponse, type ListSuppressionsParams, type ListSuppressionsResponse, type ListTemplatesParams, type ListTemplatesResponse, type ListWebhooksResponse, type MessageContentResponse, type MessageStatusRecipient, type MessageStatusResponse, NetworkError, NotFoundError, Outbound, type OutboundConfig, OutboundError, type QuotaResponse, RateLimitError, type RecountContactListResponse, type RejectedEmail, type RequestOverrides, type ResolvedConfig, type SearchSuppressionsParams, type SearchSuppressionsResponse, type SendEmailParams, type SendEmailResponse, ServerError, type Suppression, type SuppressionReason, type SuppressionResponse, type Template, type TemplateBulkRecipient, type TemplateBulkSendParams, type TemplateBulkSendResponse, type TemplatePreviewParams, type TemplatePreviewResponse, type TemplateResponse, type TemplateSendParams, type TemplateStatsResponse, TimeoutError, type UpdateContactListParams, type UpdateContactParams, type UpdateTemplateParams, type UpdateWebhookParams, type UpdateWebhookResponse, type VariableMapping, type Webhook, type WebhookEvent, type WebhookEventDetails, type WebhookEventStatus, type WebhookRetryStrategy };
|
package/dist/index.js
CHANGED
|
@@ -247,17 +247,6 @@ var EmailResource = class {
|
|
|
247
247
|
async send(params, overrides) {
|
|
248
248
|
return this.http.post("/v1/email/send", params, overrides?.apiKey);
|
|
249
249
|
}
|
|
250
|
-
/**
|
|
251
|
-
* Send to many recipients at once.
|
|
252
|
-
*
|
|
253
|
-
* Three shapes, discriminated by what you pass:
|
|
254
|
-
* - `emails[]` with a full `htmlBody` each — the original behaviour, unchanged.
|
|
255
|
-
* - `emails[]` + a shared `htmlBody` + per-recipient `variables` — MAIL MERGE.
|
|
256
|
-
* The template crosses the wire once instead of once per recipient.
|
|
257
|
-
* - `listId` (+ `mapping`) — a saved contact list, with NO recipient cap. Returns
|
|
258
|
-
* a `ListSendResponse` with `mode: 'list'` and a job id you can poll; the
|
|
259
|
-
* server materializes the recipients in the background.
|
|
260
|
-
*/
|
|
261
250
|
async bulk(params, overrides) {
|
|
262
251
|
return this.http.post("/v1/email/bulk", params, overrides?.apiKey);
|
|
263
252
|
}
|
|
@@ -344,13 +333,6 @@ var TemplatesResource = class {
|
|
|
344
333
|
async send(params, overrides) {
|
|
345
334
|
return this.http.post("/v1/email-templates/send", params, overrides?.apiKey);
|
|
346
335
|
}
|
|
347
|
-
/**
|
|
348
|
-
* Send a template to many recipients.
|
|
349
|
-
*
|
|
350
|
-
* Pass `recipients[]` (up to 1000) for an inline send, or `listId` (+ `mapping`)
|
|
351
|
-
* to send to a whole saved contact list with no recipient cap — the server
|
|
352
|
-
* expands the list in the background and returns `mode: 'list'` with a job id.
|
|
353
|
-
*/
|
|
354
336
|
async bulkSend(params, overrides) {
|
|
355
337
|
return this.http.post("/v1/email-templates/bulk", params, overrides?.apiKey);
|
|
356
338
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/resources/email.ts","../src/resources/templates.ts","../src/resources/suppressions.ts","../src/resources/webhooks.ts","../src/resources/dashboard.ts","../src/resources/quota.ts","../src/resources/campaigns.ts","../src/resources/contactLists.ts","../src/client.ts"],"sourcesContent":["export { Outbound } from './client';\n\n// Error classes\nexport {\n OutboundError,\n BadRequestError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n RateLimitError,\n ServerError,\n TimeoutError,\n NetworkError,\n} from './errors';\n\n// All types\nexport type {\n OutboundConfig,\n ResolvedConfig,\n RequestOverrides,\n SendEmailParams,\n Attachment,\n SendEmailResponse,\n BulkEmailParams,\n BulkEmailRecipient,\n BulkEmailResponse,\n BulkResponseRecipient,\n EmailJob,\n JobStatusResponse,\n MessageStatusResponse,\n MessageStatusRecipient,\n MessageContentResponse,\n EmailRecipientStatus,\n EmailStatus,\n CancelEmailParams,\n CancelEmailResponse,\n CreateTemplateParams,\n UpdateTemplateParams,\n ListTemplatesParams,\n ListTemplatesResponse,\n Template,\n TemplateResponse,\n TemplateSendParams,\n TemplateBulkSendParams,\n TemplateBulkRecipient,\n TemplateBulkSendResponse,\n TemplatePreviewParams,\n TemplatePreviewResponse,\n TemplateStatsResponse,\n ListSuppressionsParams,\n ListSuppressionsResponse,\n Suppression,\n SuppressionReason,\n AddSuppressionParams,\n SuppressionResponse,\n EmailList,\n RejectedEmail,\n SearchSuppressionsParams,\n SearchSuppressionsResponse,\n BulkAddSuppressionsParams,\n BulkAddSuppressionsResponse,\n BulkRemoveSuppressionsParams,\n BulkRemoveSuppressionsResponse,\n WebhookEvent,\n IncomingWebhookEvent,\n IncomingWebhookPayload,\n WebhookEventStatus,\n WebhookEventDetails,\n IncomingWebhookEventV2,\n IncomingWebhookPayloadV2,\n AnyIncomingWebhookPayload,\n WebhookRetryStrategy,\n CreateWebhookParams,\n UpdateWebhookParams,\n Webhook,\n CreateWebhookResponse,\n UpdateWebhookResponse,\n ListWebhooksResponse,\n DashboardResponse,\n DedicatedIpWarmup,\n IpPoolStatus,\n QuotaResponse,\n GlobalQuotaResponse,\n CampaignStatus,\n ListCampaignsParams,\n CampaignSummary,\n ListCampaignsResponse,\n CampaignAnalyticsParams,\n CampaignTotals,\n CampaignRates,\n CampaignTimeseriesPoint,\n CampaignDomainStat,\n CampaignBounceReason,\n CampaignAnalytics,\n // Contact lists\n ContactStatus,\n ContactStatusReason,\n ContactList,\n ContactListDetail,\n Contact,\n CreateContactListParams,\n UpdateContactListParams,\n ListContactListsParams,\n ListContactListsResponse,\n ImportContactRow,\n ImportContactsParams,\n ImportContactsResponse,\n ListContactsParams,\n ListContactsResponse,\n AddContactParams,\n UpdateContactParams,\n BulkDeleteContactsParams,\n BulkDeleteContactsResponse,\n ContactListFieldsResponse,\n RecountContactListResponse,\n AcceptedResponse,\n VariableMapping,\n ListSendResponse,\n // Previously missing from the public surface even though quota.check() returns it.\n CheckQuotaResponse,\n} from './types';\n","export class OutboundError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly details?: unknown,\n public readonly requestId?: string,\n ) {\n super(message);\n this.name = 'OutboundError';\n }\n}\n\nexport class BadRequestError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 400, details, requestId);\n this.name = 'BadRequestError';\n }\n}\n\nexport class AuthenticationError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 401, details, requestId);\n this.name = 'AuthenticationError';\n }\n}\n\nexport class ForbiddenError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 403, details, requestId);\n this.name = 'ForbiddenError';\n }\n}\n\nexport class NotFoundError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 404, details, requestId);\n this.name = 'NotFoundError';\n }\n}\n\nexport class ConflictError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 409, details, requestId);\n this.name = 'ConflictError';\n }\n}\n\nexport class RateLimitError extends OutboundError {\n public readonly retryAfter?: number;\n\n constructor(message: string, retryAfter?: number, details?: unknown, requestId?: string) {\n super(message, 429, details, requestId);\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\nexport class ServerError extends OutboundError {\n constructor(message: string, statusCode: number = 500, details?: unknown, requestId?: string) {\n super(message, statusCode, details, requestId);\n this.name = 'ServerError';\n }\n}\n\nexport class TimeoutError extends OutboundError {\n constructor(message: string = 'Request timed out') {\n super(message, 0);\n this.name = 'TimeoutError';\n }\n}\n\nexport class NetworkError extends OutboundError {\n constructor(message: string = 'Network request failed') {\n super(message, 0);\n this.name = 'NetworkError';\n }\n}\n","import type { ResolvedConfig } from './types';\nimport {\n OutboundError,\n BadRequestError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n RateLimitError,\n ServerError,\n TimeoutError,\n NetworkError,\n} from './errors';\n\nexport interface RequestOptions {\n body?: unknown;\n params?: Record<string, unknown>;\n}\n\nexport class HttpClient {\n constructor(private config: ResolvedConfig) {}\n\n async get<T>(path: string, params?: Record<string, unknown>, apiKey?: string): Promise<T> {\n return this.request<T>('GET', path, { params }, apiKey);\n }\n\n async post<T>(path: string, body?: unknown, apiKey?: string): Promise<T> {\n return this.request<T>('POST', path, { body }, apiKey);\n }\n\n async patch<T>(path: string, body?: unknown, apiKey?: string): Promise<T> {\n return this.request<T>('PATCH', path, { body }, apiKey);\n }\n\n async delete<T>(path: string, apiKey?: string): Promise<T> {\n return this.request<T>('DELETE', path, undefined, apiKey);\n }\n\n private resolveApiKey(apiKey?: string): string {\n const key = apiKey || this.config.apiKey;\n if (!key) {\n throw new AuthenticationError(\n 'API key is required. Pass it to the constructor or provide it per method call.',\n );\n }\n return key;\n }\n\n private async request<T>(method: string, path: string, options?: RequestOptions, apiKey?: string): Promise<T> {\n const resolvedKey = this.resolveApiKey(apiKey);\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const url = this.buildUrl(path, options?.params);\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n const response = await fetch(url, {\n method,\n headers: {\n 'X-Api-Key': resolvedKey,\n 'Content-Type': 'application/json',\n },\n body: options?.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const error = await this.parseError(response);\n\n // Only retry on 429 and 5xx\n if (response.status === 429 || response.status >= 500) {\n lastError = error;\n\n if (attempt < this.config.maxRetries) {\n const retryAfter = error instanceof RateLimitError && error.retryAfter\n ? error.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n\n await this.sleep(retryAfter);\n continue;\n }\n }\n\n throw error;\n } catch (err) {\n if (err instanceof OutboundError) {\n // Already a typed error from parseError — check if retryable\n if ((err.statusCode === 429 || err.statusCode >= 500) && attempt < this.config.maxRetries) {\n lastError = err;\n const retryAfter = err instanceof RateLimitError && err.retryAfter\n ? err.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n await this.sleep(retryAfter);\n continue;\n }\n throw err;\n }\n\n if (err instanceof DOMException && err.name === 'AbortError') {\n lastError = new TimeoutError(`Request timed out after ${this.config.timeout}ms`);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n\n lastError = new NetworkError((err as Error).message);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n }\n\n throw lastError || new NetworkError('Request failed after retries');\n }\n\n private buildUrl(path: string, params?: Record<string, unknown>): string {\n const base = this.config.baseUrl.replace(/\\/+$/, '');\n const url = new URL(`${base}${path}`);\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n }\n\n private async parseError(response: Response): Promise<OutboundError> {\n let body: { error?: string; message?: string; details?: unknown } = {};\n const requestId = response.headers.get('x-request-id') || undefined;\n\n try {\n body = (await response.json()) as typeof body;\n } catch {\n // Response may not be JSON\n }\n\n const message = body.error || body.message || `HTTP ${response.status}`;\n const details = body.details;\n\n switch (response.status) {\n case 400:\n return new BadRequestError(message, details, requestId);\n case 401:\n return new AuthenticationError(message, details, requestId);\n case 403:\n return new ForbiddenError(message, details, requestId);\n case 404:\n return new NotFoundError(message, details, requestId);\n case 409:\n return new ConflictError(message, details, requestId);\n case 429: {\n const retryAfter = response.headers.get('retry-after');\n return new RateLimitError(\n message,\n retryAfter ? parseInt(retryAfter, 10) : undefined,\n details,\n requestId,\n );\n }\n default:\n if (response.status >= 500) {\n return new ServerError(message, response.status, details, requestId);\n }\n return new OutboundError(message, response.status, details, requestId);\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n SendEmailParams,\n SendEmailResponse,\n BulkEmailParams,\n BulkEmailResponse,\n ListSendResponse,\n JobStatusResponse,\n MessageStatusResponse,\n MessageContentResponse,\n CancelEmailParams,\n CancelEmailResponse,\n RequestOverrides,\n} from '../types';\n\nexport class EmailResource {\n constructor(private http: HttpClient) {}\n\n async send(params: SendEmailParams, overrides?: RequestOverrides): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>('/v1/email/send', params, overrides?.apiKey);\n }\n\n /**\n * Send to many recipients at once.\n *\n * Three shapes, discriminated by what you pass:\n * - `emails[]` with a full `htmlBody` each — the original behaviour, unchanged.\n * - `emails[]` + a shared `htmlBody` + per-recipient `variables` — MAIL MERGE.\n * The template crosses the wire once instead of once per recipient.\n * - `listId` (+ `mapping`) — a saved contact list, with NO recipient cap. Returns\n * a `ListSendResponse` with `mode: 'list'` and a job id you can poll; the\n * server materializes the recipients in the background.\n */\n async bulk(params: BulkEmailParams, overrides?: RequestOverrides): Promise<BulkEmailResponse | ListSendResponse> {\n return this.http.post<BulkEmailResponse | ListSendResponse>('/v1/email/bulk', params, overrides?.apiKey);\n }\n\n async status(jobId: string, overrides?: RequestOverrides): Promise<JobStatusResponse> {\n return this.http.get<JobStatusResponse>(`/v1/email/status/${encodeURIComponent(jobId)}`, undefined, overrides?.apiKey);\n }\n\n /**\n * Look up the current status of a single message by its `messageId` — the ID\n * returned from `send()`/`bulk()` and included in webhook payloads. Useful for\n * reconciling a message whose webhook was missed.\n *\n * Accepts **only** a message ID — not a job ID or SES message ID. The message\n * must belong to the tenant the API key is scoped to; otherwise a `NotFoundError`\n * is thrown. The status reflects the latest event recorded by the SES event\n * pipeline.\n */\n async getMessageStatus(messageId: string, overrides?: RequestOverrides): Promise<MessageStatusResponse> {\n return this.http.get<MessageStatusResponse>(`/v1/email/messages/${encodeURIComponent(messageId)}/status`, undefined, overrides?.apiKey);\n }\n\n /**\n * Fetch the content that was sent for a single message by its `messageId` — the\n * subject, envelope and `htmlBody`/`textBody`, exactly as sent (the HTML includes\n * the appended unsubscribe footer). This is the same content the dashboard renders\n * in its \"Preview\", so you can reconstruct or re-display a sent email on your side.\n *\n * Accepts **only** a message ID — not a job ID or SES message ID. The message must\n * belong to the tenant the API key is scoped to; otherwise a `NotFoundError` is\n * thrown. Attachments are not inlined.\n */\n async getMessageContent(messageId: string, overrides?: RequestOverrides): Promise<MessageContentResponse> {\n return this.http.get<MessageContentResponse>(`/v1/email/messages/${encodeURIComponent(messageId)}/content`, undefined, overrides?.apiKey);\n }\n\n /**\n * Cancel all queued/processing emails for a campaign or job.\n * Provide either `campaignId` (cancels all jobs in that campaign) or `jobId` (cancels one job).\n * Already-sent emails cannot be recalled — only recipients still in `queued` or `processing` state are cancelled.\n */\n async cancel(params: CancelEmailParams, overrides?: RequestOverrides): Promise<CancelEmailResponse> {\n if (!params.campaignId && !params.jobId) {\n throw new Error('cancel() requires either campaignId or jobId');\n }\n return this.http.post<CancelEmailResponse>('/v1/email/cancel', params, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateTemplateParams,\n UpdateTemplateParams,\n ListTemplatesParams,\n ListTemplatesResponse,\n Template,\n TemplateResponse,\n TemplateSendParams,\n SendEmailResponse,\n TemplateBulkSendParams,\n TemplateBulkSendResponse,\n ListSendResponse,\n TemplatePreviewParams,\n TemplatePreviewResponse,\n TemplateStatsResponse,\n RequestOverrides,\n} from '../types';\n\nexport class TemplatesResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateTemplateParams, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>('/v1/email-templates', params, overrides?.apiKey);\n }\n\n async list(params?: ListTemplatesParams, overrides?: RequestOverrides): Promise<ListTemplatesResponse> {\n return this.http.get<ListTemplatesResponse>('/v1/email-templates', params as Record<string, unknown>, overrides?.apiKey);\n }\n\n async *listAll(params?: Omit<ListTemplatesParams, 'page'>, overrides?: RequestOverrides): AsyncGenerator<Template> {\n let page = 1;\n const limit = params?.limit || 20;\n\n while (true) {\n const result = await this.list({ ...params, page, limit }, overrides);\n for (const template of result.templates) {\n yield template;\n }\n if (result.templates.length < limit) break;\n page++;\n }\n }\n\n async get(id: string, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.get<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}`, undefined, overrides?.apiKey);\n }\n\n async update(id: string, params: UpdateTemplateParams, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.patch<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}`, params, overrides?.apiKey);\n }\n\n async delete(id: string, overrides?: RequestOverrides): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(`/v1/email-templates/${encodeURIComponent(id)}`, overrides?.apiKey);\n }\n\n async duplicate(id: string, params?: { name?: string }, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}/duplicate`, params, overrides?.apiKey);\n }\n\n async preview(id: string, params?: TemplatePreviewParams, overrides?: RequestOverrides): Promise<TemplatePreviewResponse> {\n return this.http.post<TemplatePreviewResponse>(`/v1/email-templates/${encodeURIComponent(id)}/preview`, params, overrides?.apiKey);\n }\n\n async send(params: TemplateSendParams, overrides?: RequestOverrides): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>('/v1/email-templates/send', params, overrides?.apiKey);\n }\n\n /**\n * Send a template to many recipients.\n *\n * Pass `recipients[]` (up to 1000) for an inline send, or `listId` (+ `mapping`)\n * to send to a whole saved contact list with no recipient cap — the server\n * expands the list in the background and returns `mode: 'list'` with a job id.\n */\n async bulkSend(params: TemplateBulkSendParams, overrides?: RequestOverrides): Promise<TemplateBulkSendResponse | ListSendResponse> {\n return this.http.post<TemplateBulkSendResponse | ListSendResponse>('/v1/email-templates/bulk', params, overrides?.apiKey);\n }\n\n async stats(overrides?: RequestOverrides): Promise<TemplateStatsResponse> {\n return this.http.get<TemplateStatsResponse>('/v1/email-templates/stats', undefined, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ListSuppressionsParams,\n ListSuppressionsResponse,\n AddSuppressionParams,\n SuppressionResponse,\n Suppression,\n EmailList,\n SearchSuppressionsParams,\n SearchSuppressionsResponse,\n BulkAddSuppressionsParams,\n BulkAddSuppressionsResponse,\n BulkRemoveSuppressionsParams,\n BulkRemoveSuppressionsResponse,\n RequestOverrides,\n} from '../types';\n\n/**\n * The API takes a comma-separated list on the wire. Arrays are the ergonomic\n * form for callers, so normalize here rather than making every caller join.\n */\nfunction toEmailList(emails: EmailList): string {\n return Array.isArray(emails) ? emails.join(',') : emails;\n}\n\nexport class SuppressionsResource {\n constructor(private http: HttpClient) {}\n\n async list(params?: ListSuppressionsParams, overrides?: RequestOverrides): Promise<ListSuppressionsResponse> {\n return this.http.get<ListSuppressionsResponse>('/v1/tenants/suppressions', params as Record<string, unknown>, overrides?.apiKey);\n }\n\n async *listAll(params?: Omit<ListSuppressionsParams, 'page'>, overrides?: RequestOverrides): AsyncGenerator<Suppression> {\n let page = 1;\n const limit = params?.limit || 50;\n\n while (true) {\n const result = await this.list({ ...params, page, limit }, overrides);\n for (const suppression of result.suppressions) {\n yield suppression;\n }\n if (result.suppressions.length < limit) break;\n page++;\n }\n }\n\n /**\n * Look up specific addresses on the suppression list — exact, case-insensitive,\n * up to 100 per request. Every address is validated server-side before it is\n * queried, so a malformed entry comes back in `rejected` instead of failing the\n * whole call.\n *\n * For substring matching (e.g. every address on a domain), use\n * `list({ search: 'acme.com' })` instead.\n */\n async search(params: SearchSuppressionsParams, overrides?: RequestOverrides): Promise<SearchSuppressionsResponse> {\n return this.http.get<SearchSuppressionsResponse>(\n '/v1/tenants/suppressions/search',\n { emails: toEmailList(params.emails) },\n overrides?.apiKey,\n );\n }\n\n async add(params: AddSuppressionParams, overrides?: RequestOverrides): Promise<SuppressionResponse> {\n return this.http.post<SuppressionResponse>('/v1/tenants/suppressions', params, overrides?.apiKey);\n }\n\n /**\n * Suppress up to 1000 addresses in one request. Valid addresses are added and\n * reported in `added`; ones already on the list come back in `alreadySuppressed`\n * with their existing record untouched; ones that fail validation come back in\n * `rejected` and are never written.\n */\n async bulkAdd(params: BulkAddSuppressionsParams, overrides?: RequestOverrides): Promise<BulkAddSuppressionsResponse> {\n return this.http.post<BulkAddSuppressionsResponse>(\n '/v1/tenants/suppressions/bulk/add',\n { emails: toEmailList(params.emails), reason: params.reason },\n overrides?.apiKey,\n );\n }\n\n /**\n * Unsuppress up to 1000 addresses in one request. Unlike `remove()`, an address\n * that is not on the list is not an error: it is reported in `notFound`, so one\n * bad entry cannot fail the batch.\n */\n async bulkRemove(params: BulkRemoveSuppressionsParams, overrides?: RequestOverrides): Promise<BulkRemoveSuppressionsResponse> {\n return this.http.post<BulkRemoveSuppressionsResponse>(\n '/v1/tenants/suppressions/bulk/remove',\n { emails: toEmailList(params.emails) },\n overrides?.apiKey,\n );\n }\n\n async remove(email: string, overrides?: RequestOverrides): Promise<{ message: string }> {\n return this.http.delete<{ message: string }>(`/v1/tenants/suppressions/${encodeURIComponent(email)}`, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateWebhookParams,\n CreateWebhookResponse,\n UpdateWebhookParams,\n UpdateWebhookResponse,\n ListWebhooksResponse,\n RequestOverrides,\n} from '../types';\n\nexport class WebhooksResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateWebhookParams, overrides?: RequestOverrides): Promise<CreateWebhookResponse> {\n return this.http.post<CreateWebhookResponse>('/v1/tenants/webhooks', params, overrides?.apiKey);\n }\n\n async list(overrides?: RequestOverrides): Promise<ListWebhooksResponse> {\n return this.http.get<ListWebhooksResponse>('/v1/tenants/webhooks', undefined, overrides?.apiKey);\n }\n\n async update(id: string, params: UpdateWebhookParams, overrides?: RequestOverrides): Promise<UpdateWebhookResponse> {\n return this.http.patch<UpdateWebhookResponse>(`/v1/tenants/webhooks/${encodeURIComponent(id)}`, params, overrides?.apiKey);\n }\n\n async delete(id: string, overrides?: RequestOverrides): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(`/v1/tenants/webhooks/${encodeURIComponent(id)}`, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type { DashboardResponse, QuotaResponse, RequestOverrides } from '../types';\n\nexport class DashboardResource {\n constructor(private http: HttpClient) {}\n\n async get(overrides?: RequestOverrides): Promise<DashboardResponse> {\n return this.http.get<DashboardResponse>('/v1/tenants/dashboard', undefined, overrides?.apiKey);\n }\n\n async quota(overrides?: RequestOverrides): Promise<QuotaResponse> {\n return this.http.get<QuotaResponse>('/v1/tenants/quota', undefined, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n GlobalQuotaResponse,\n CheckQuotaResponse,\n RequestOverrides,\n} from '../types';\n\n/**\n * Account-global quota: the shared SES 24h cap across ALL tenants/sources.\n *\n * Sends are NOT gated — `email.send`/`email.bulk` always submit. This is an\n * OPT-IN routing aid: call `check(count)` before a batch to ask whether the\n * shared pool has room and atomically hold it against concurrent callers. An\n * `ok:false` is a normal answer (route that batch to a fallback vendor).\n *\n * `global()` is a cheap point-in-time read; `check()` is the atomic, concurrency-\n * safe primitive that most callers want.\n */\nexport class QuotaResource {\n constructor(private http: HttpClient) {}\n\n /** Read the global quota snapshot (point-in-time). For concurrency safety use `check()`. */\n async global(overrides?: RequestOverrides): Promise<GlobalQuotaResponse> {\n return this.http.get<GlobalQuotaResponse>('/v1/quota/global', undefined, overrides?.apiKey);\n }\n\n /**\n * Opt-in quota check. Atomically holds `count` against the shared pool and\n * returns whether it fit — so two concurrent `check(300)` calls against 500 of\n * headroom can't both succeed. `ok:false` is a normal response (route to a\n * fallback vendor), not an error. The hold auto-expires after `ttlSeconds`;\n * there is no reservationId and nothing to release.\n */\n async check(count: number, overrides?: RequestOverrides): Promise<CheckQuotaResponse> {\n return this.http.post<CheckQuotaResponse>('/v1/quota/check', { count }, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ListCampaignsParams,\n ListCampaignsResponse,\n CampaignAnalyticsParams,\n CampaignAnalytics,\n RequestOverrides,\n} from '../types';\n\nexport class CampaignsResource {\n constructor(private http: HttpClient) {}\n\n /** List the tenant's campaigns with headline send stats. */\n async list(params?: ListCampaignsParams, overrides?: RequestOverrides): Promise<ListCampaignsResponse> {\n return this.http.get<ListCampaignsResponse>(\n '/v1/tenants/campaigns',\n params as Record<string, unknown> | undefined,\n overrides?.apiKey,\n );\n }\n\n /** Full analytics report for one campaign (totals, rates, timeseries, breakdowns). */\n async analytics(\n campaignId: string,\n params?: CampaignAnalyticsParams,\n overrides?: RequestOverrides,\n ): Promise<CampaignAnalytics> {\n return this.http.get<CampaignAnalytics>(\n `/v1/tenants/campaigns/${encodeURIComponent(campaignId)}/analytics`,\n params as Record<string, unknown> | undefined,\n overrides?.apiKey,\n );\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ContactList,\n ContactListDetail,\n CreateContactListParams,\n UpdateContactListParams,\n ListContactListsParams,\n ListContactListsResponse,\n ImportContactsParams,\n ImportContactsResponse,\n ListContactsParams,\n ListContactsResponse,\n AddContactParams,\n UpdateContactParams,\n Contact,\n BulkDeleteContactsParams,\n BulkDeleteContactsResponse,\n ContactListFieldsResponse,\n RecountContactListResponse,\n AcceptedResponse,\n RequestOverrides,\n} from '../types';\n\n/**\n * Contact lists: reusable audiences you can send to without a recipient limit.\n *\n * The per-request cap on `email.bulk` / `templates.bulkSend` exists because those\n * carry their recipients in the request body. A list send carries only a `listId`,\n * and the server expands the list in the background — so there is no cap, and the\n * caller gets one job id to track however large the audience is.\n *\n * ── Address hygiene ──\n * Every imported address is sanitized (display-name unwrapping, `mailto:`,\n * zero-width characters, quotes, case) and then validated with the SAME rules the\n * send path applies. Addresses that fail are STORED with `status: 'invalid'` rather\n * than discarded, so you can list them, export them and fix them. Addresses on your\n * suppression list are stored with the matching status. Only `subscribed` contacts\n * are ever sent to, and bounces, complaints and unsubscribes flow back onto the\n * contact automatically.\n */\nexport class ContactListsResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateContactListParams, overrides?: RequestOverrides): Promise<{ message: string; list: ContactList }> {\n return this.http.post('/v1/contact-lists', params, overrides?.apiKey);\n }\n\n async list(params?: ListContactListsParams, overrides?: RequestOverrides): Promise<ListContactListsResponse> {\n return this.http.get<ListContactListsResponse>('/v1/contact-lists', params as Record<string, unknown>, overrides?.apiKey);\n }\n\n /** Auto-paginating iterator over every contact list, mirroring templates.listAll(). */\n async *listAll(params?: Omit<ListContactListsParams, 'page'>, overrides?: RequestOverrides): AsyncGenerator<ContactList> {\n const limit = params?.limit ?? 100;\n let page = 1;\n for (;;) {\n const result = await this.list({ ...params, page, limit }, overrides);\n for (const item of result.lists) yield item;\n if (result.lists.length < limit) return;\n page += 1;\n }\n }\n\n /** A list plus its per-status breakdown (how many are sendable, invalid, bounced...). */\n async get(listId: string, overrides?: RequestOverrides): Promise<ContactListDetail> {\n return this.http.get<ContactListDetail>(`/v1/contact-lists/${encodeURIComponent(listId)}`, undefined, overrides?.apiKey);\n }\n\n async update(listId: string, params: UpdateContactListParams, overrides?: RequestOverrides): Promise<{ message: string; list: ContactList }> {\n return this.http.patch(`/v1/contact-lists/${encodeURIComponent(listId)}`, params, overrides?.apiKey);\n }\n\n /**\n * Delete a list. Returns 202: the contacts are removed by a background job in\n * chunks, so a multi-million-row list does not block on one enormous transaction.\n * Fails with a conflict while a send is still expanding this list.\n */\n async delete(listId: string, overrides?: RequestOverrides): Promise<AcceptedResponse> {\n return this.http.delete<AcceptedResponse>(`/v1/contact-lists/${encodeURIComponent(listId)}`, overrides?.apiKey);\n }\n\n /**\n * Import a chunk of contacts (max 1000 rows per call).\n *\n * Pass the same `importId` with an incrementing `chunkIndex` for every chunk of\n * one file: that pair makes a retried chunk a no-op instead of a double-insert,\n * so a network failure mid-upload is safe to retry blindly.\n *\n * `onExisting: 'update'` merges attributes into contacts already in the list. It\n * never re-subscribes someone who bounced, complained or opted out.\n */\n async importContacts(listId: string, params: ImportContactsParams, overrides?: RequestOverrides): Promise<ImportContactsResponse> {\n return this.http.post<ImportContactsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/import`, params, overrides?.apiKey,\n );\n }\n\n /**\n * List contacts. KEYSET paginated: pass the previous response's\n * `pagination.nextCursor` as `cursor` to advance. There is no page number,\n * because offset paging degrades badly past a few hundred pages.\n */\n async contacts(listId: string, params?: ListContactsParams, overrides?: RequestOverrides): Promise<ListContactsResponse> {\n return this.http.get<ListContactsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts`, params as Record<string, unknown>, overrides?.apiKey,\n );\n }\n\n /** Auto-paginating iterator over every contact in a list. */\n async *contactsAll(listId: string, params?: Omit<ListContactsParams, 'cursor'>, overrides?: RequestOverrides): AsyncGenerator<Contact> {\n let cursor: string | undefined;\n for (;;) {\n const result = await this.contacts(listId, { ...params, cursor }, overrides);\n for (const contact of result.contacts) yield contact;\n if (!result.pagination.hasMore || !result.pagination.nextCursor) return;\n cursor = result.pagination.nextCursor;\n }\n }\n\n async addContact(listId: string, params: AddContactParams, overrides?: RequestOverrides): Promise<{ message: string; contact: Contact }> {\n return this.http.post(`/v1/contact-lists/${encodeURIComponent(listId)}/contacts`, params, overrides?.apiKey);\n }\n\n /** `attributes` REPLACES the stored object wholesale here; import merges instead. */\n async updateContact(listId: string, contactId: string, params: UpdateContactParams, overrides?: RequestOverrides): Promise<{ message: string; contact: Contact }> {\n return this.http.patch(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/${encodeURIComponent(contactId)}`, params, overrides?.apiKey,\n );\n }\n\n async deleteContact(listId: string, contactId: string, overrides?: RequestOverrides): Promise<void> {\n await this.http.delete(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/${encodeURIComponent(contactId)}`, overrides?.apiKey,\n );\n }\n\n /**\n * Delete many contacts. Pass `contactIds` or `emails` (up to 1000), or a FILTER\n * — `{ status: 'invalid' }` or `{ all: true }` — which is how you clear tens of\n * thousands of dead addresses in one small request. Filtered deletes return 202\n * and run in the background.\n */\n async bulkDeleteContacts(listId: string, params: BulkDeleteContactsParams, overrides?: RequestOverrides): Promise<BulkDeleteContactsResponse> {\n return this.http.post<BulkDeleteContactsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/bulk-delete`, params, overrides?.apiKey,\n );\n }\n\n /**\n * The column names available for send-time variable mapping, with a sample value\n * for each. This is what tells you which `mapping` keys a list will accept.\n */\n async fields(listId: string, options?: { refresh?: boolean }, overrides?: RequestOverrides): Promise<ContactListFieldsResponse> {\n return this.http.get<ContactListFieldsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/fields`,\n options?.refresh ? { refresh: 'true' } : undefined,\n overrides?.apiKey,\n );\n }\n\n /**\n * Re-run validation and re-sync suppression across the whole list. Useful after a\n * bulk suppression import, or to refresh a list that has been sitting. Returns 202.\n */\n async revalidate(listId: string, overrides?: RequestOverrides): Promise<AcceptedResponse> {\n return this.http.post<AcceptedResponse>(`/v1/contact-lists/${encodeURIComponent(listId)}/revalidate`, {}, overrides?.apiKey);\n }\n\n /** Reconcile the denormalized contact count with an exact COUNT. */\n async recount(listId: string, overrides?: RequestOverrides): Promise<RecountContactListResponse> {\n return this.http.post<RecountContactListResponse>(`/v1/contact-lists/${encodeURIComponent(listId)}/recount`, {}, overrides?.apiKey);\n }\n}\n","import { HttpClient } from './http';\nimport { EmailResource } from './resources/email';\nimport { TemplatesResource } from './resources/templates';\nimport { SuppressionsResource } from './resources/suppressions';\nimport { WebhooksResource } from './resources/webhooks';\nimport { DashboardResource } from './resources/dashboard';\nimport { QuotaResource } from './resources/quota';\nimport { CampaignsResource } from './resources/campaigns';\nimport { ContactListsResource } from './resources/contactLists';\nimport type { OutboundConfig, ResolvedConfig } from './types';\n\nconst BASE_URL = 'https://outbound-api.unionstack.in';\n\nexport class Outbound {\n readonly email: EmailResource;\n readonly templates: TemplatesResource;\n readonly suppressions: SuppressionsResource;\n readonly webhooks: WebhooksResource;\n readonly dashboard: DashboardResource;\n readonly quota: QuotaResource;\n readonly campaigns: CampaignsResource;\n readonly contactLists: ContactListsResource;\n\n constructor(config?: OutboundConfig) {\n const resolved: ResolvedConfig = {\n apiKey: config?.apiKey,\n baseUrl: config?.baseUrl || BASE_URL,\n timeout: config?.timeout ?? 30_000,\n maxRetries: config?.maxRetries ?? 3,\n retryDelay: config?.retryDelay ?? 1000,\n };\n\n const http = new HttpClient(resolved);\n\n this.email = new EmailResource(http);\n this.templates = new TemplatesResource(http);\n this.suppressions = new SuppressionsResource(http);\n this.webhooks = new WebhooksResource(http);\n this.dashboard = new DashboardResource(http);\n this.quota = new QuotaResource(http);\n this.campaigns = new CampaignsResource(http);\n this.contactLists = new ContactListsResource(http);\n }\n\n /**\n * Verify a webhook signature using HMAC-SHA256.\n * Use this in your webhook handler to validate incoming requests.\n */\n static verifyWebhookSignature(\n payload: string | Buffer,\n signature: string,\n secret: string,\n ): boolean {\n // Dynamic import to keep browser-compatible at the type level\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const crypto = require('crypto') as typeof import('crypto');\n const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');\n try {\n return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/resources/email.ts","../src/resources/templates.ts","../src/resources/suppressions.ts","../src/resources/webhooks.ts","../src/resources/dashboard.ts","../src/resources/quota.ts","../src/resources/campaigns.ts","../src/resources/contactLists.ts","../src/client.ts"],"sourcesContent":["export { Outbound } from './client';\n\n// Error classes\nexport {\n OutboundError,\n BadRequestError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n RateLimitError,\n ServerError,\n TimeoutError,\n NetworkError,\n} from './errors';\n\n// All types\nexport type {\n OutboundConfig,\n ResolvedConfig,\n RequestOverrides,\n SendEmailParams,\n Attachment,\n SendEmailResponse,\n BulkEmailParams,\n BulkEmailRecipient,\n BulkEmailResponse,\n BulkResponseRecipient,\n EmailJob,\n JobStatusResponse,\n MessageStatusResponse,\n MessageStatusRecipient,\n MessageContentResponse,\n EmailRecipientStatus,\n EmailStatus,\n CancelEmailParams,\n CancelEmailResponse,\n CreateTemplateParams,\n UpdateTemplateParams,\n ListTemplatesParams,\n ListTemplatesResponse,\n Template,\n TemplateResponse,\n TemplateSendParams,\n TemplateBulkSendParams,\n TemplateBulkRecipient,\n TemplateBulkSendResponse,\n TemplatePreviewParams,\n TemplatePreviewResponse,\n TemplateStatsResponse,\n ListSuppressionsParams,\n ListSuppressionsResponse,\n Suppression,\n SuppressionReason,\n AddSuppressionParams,\n SuppressionResponse,\n EmailList,\n RejectedEmail,\n SearchSuppressionsParams,\n SearchSuppressionsResponse,\n BulkAddSuppressionsParams,\n BulkAddSuppressionsResponse,\n BulkRemoveSuppressionsParams,\n BulkRemoveSuppressionsResponse,\n WebhookEvent,\n IncomingWebhookEvent,\n IncomingWebhookPayload,\n WebhookEventStatus,\n WebhookEventDetails,\n IncomingWebhookEventV2,\n IncomingWebhookPayloadV2,\n AnyIncomingWebhookPayload,\n WebhookRetryStrategy,\n CreateWebhookParams,\n UpdateWebhookParams,\n Webhook,\n CreateWebhookResponse,\n UpdateWebhookResponse,\n ListWebhooksResponse,\n DashboardResponse,\n DedicatedIpWarmup,\n IpPoolStatus,\n QuotaResponse,\n GlobalQuotaResponse,\n CampaignStatus,\n ListCampaignsParams,\n CampaignSummary,\n ListCampaignsResponse,\n CampaignAnalyticsParams,\n CampaignTotals,\n CampaignRates,\n CampaignTimeseriesPoint,\n CampaignDomainStat,\n CampaignBounceReason,\n CampaignAnalytics,\n // Contact lists\n ContactStatus,\n ContactStatusReason,\n ContactList,\n ContactListDetail,\n Contact,\n CreateContactListParams,\n UpdateContactListParams,\n ListContactListsParams,\n ListContactListsResponse,\n BulkEmailMergeRecipient,\n ImportContactRow,\n ImportContactsParams,\n ImportContactsResponse,\n ListContactsParams,\n ListContactsResponse,\n AddContactParams,\n UpdateContactParams,\n BulkDeleteContactsParams,\n BulkDeleteContactsResponse,\n ContactListFieldsResponse,\n RecountContactListResponse,\n AcceptedResponse,\n VariableMapping,\n ListSendResponse,\n // Previously missing from the public surface even though quota.check() returns it.\n CheckQuotaResponse,\n} from './types';\n","export class OutboundError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly details?: unknown,\n public readonly requestId?: string,\n ) {\n super(message);\n this.name = 'OutboundError';\n }\n}\n\nexport class BadRequestError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 400, details, requestId);\n this.name = 'BadRequestError';\n }\n}\n\nexport class AuthenticationError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 401, details, requestId);\n this.name = 'AuthenticationError';\n }\n}\n\nexport class ForbiddenError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 403, details, requestId);\n this.name = 'ForbiddenError';\n }\n}\n\nexport class NotFoundError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 404, details, requestId);\n this.name = 'NotFoundError';\n }\n}\n\nexport class ConflictError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 409, details, requestId);\n this.name = 'ConflictError';\n }\n}\n\nexport class RateLimitError extends OutboundError {\n public readonly retryAfter?: number;\n\n constructor(message: string, retryAfter?: number, details?: unknown, requestId?: string) {\n super(message, 429, details, requestId);\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\nexport class ServerError extends OutboundError {\n constructor(message: string, statusCode: number = 500, details?: unknown, requestId?: string) {\n super(message, statusCode, details, requestId);\n this.name = 'ServerError';\n }\n}\n\nexport class TimeoutError extends OutboundError {\n constructor(message: string = 'Request timed out') {\n super(message, 0);\n this.name = 'TimeoutError';\n }\n}\n\nexport class NetworkError extends OutboundError {\n constructor(message: string = 'Network request failed') {\n super(message, 0);\n this.name = 'NetworkError';\n }\n}\n","import type { ResolvedConfig } from './types';\nimport {\n OutboundError,\n BadRequestError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n RateLimitError,\n ServerError,\n TimeoutError,\n NetworkError,\n} from './errors';\n\nexport interface RequestOptions {\n body?: unknown;\n params?: Record<string, unknown>;\n}\n\nexport class HttpClient {\n constructor(private config: ResolvedConfig) {}\n\n async get<T>(path: string, params?: Record<string, unknown>, apiKey?: string): Promise<T> {\n return this.request<T>('GET', path, { params }, apiKey);\n }\n\n async post<T>(path: string, body?: unknown, apiKey?: string): Promise<T> {\n return this.request<T>('POST', path, { body }, apiKey);\n }\n\n async patch<T>(path: string, body?: unknown, apiKey?: string): Promise<T> {\n return this.request<T>('PATCH', path, { body }, apiKey);\n }\n\n async delete<T>(path: string, apiKey?: string): Promise<T> {\n return this.request<T>('DELETE', path, undefined, apiKey);\n }\n\n private resolveApiKey(apiKey?: string): string {\n const key = apiKey || this.config.apiKey;\n if (!key) {\n throw new AuthenticationError(\n 'API key is required. Pass it to the constructor or provide it per method call.',\n );\n }\n return key;\n }\n\n private async request<T>(method: string, path: string, options?: RequestOptions, apiKey?: string): Promise<T> {\n const resolvedKey = this.resolveApiKey(apiKey);\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const url = this.buildUrl(path, options?.params);\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n const response = await fetch(url, {\n method,\n headers: {\n 'X-Api-Key': resolvedKey,\n 'Content-Type': 'application/json',\n },\n body: options?.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const error = await this.parseError(response);\n\n // Only retry on 429 and 5xx\n if (response.status === 429 || response.status >= 500) {\n lastError = error;\n\n if (attempt < this.config.maxRetries) {\n const retryAfter = error instanceof RateLimitError && error.retryAfter\n ? error.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n\n await this.sleep(retryAfter);\n continue;\n }\n }\n\n throw error;\n } catch (err) {\n if (err instanceof OutboundError) {\n // Already a typed error from parseError — check if retryable\n if ((err.statusCode === 429 || err.statusCode >= 500) && attempt < this.config.maxRetries) {\n lastError = err;\n const retryAfter = err instanceof RateLimitError && err.retryAfter\n ? err.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n await this.sleep(retryAfter);\n continue;\n }\n throw err;\n }\n\n if (err instanceof DOMException && err.name === 'AbortError') {\n lastError = new TimeoutError(`Request timed out after ${this.config.timeout}ms`);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n\n lastError = new NetworkError((err as Error).message);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n }\n\n throw lastError || new NetworkError('Request failed after retries');\n }\n\n private buildUrl(path: string, params?: Record<string, unknown>): string {\n const base = this.config.baseUrl.replace(/\\/+$/, '');\n const url = new URL(`${base}${path}`);\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n }\n\n private async parseError(response: Response): Promise<OutboundError> {\n let body: { error?: string; message?: string; details?: unknown } = {};\n const requestId = response.headers.get('x-request-id') || undefined;\n\n try {\n body = (await response.json()) as typeof body;\n } catch {\n // Response may not be JSON\n }\n\n const message = body.error || body.message || `HTTP ${response.status}`;\n const details = body.details;\n\n switch (response.status) {\n case 400:\n return new BadRequestError(message, details, requestId);\n case 401:\n return new AuthenticationError(message, details, requestId);\n case 403:\n return new ForbiddenError(message, details, requestId);\n case 404:\n return new NotFoundError(message, details, requestId);\n case 409:\n return new ConflictError(message, details, requestId);\n case 429: {\n const retryAfter = response.headers.get('retry-after');\n return new RateLimitError(\n message,\n retryAfter ? parseInt(retryAfter, 10) : undefined,\n details,\n requestId,\n );\n }\n default:\n if (response.status >= 500) {\n return new ServerError(message, response.status, details, requestId);\n }\n return new OutboundError(message, response.status, details, requestId);\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n SendEmailParams,\n SendEmailResponse,\n BulkEmailParams,\n BulkEmailResponse,\n ListSendResponse,\n JobStatusResponse,\n MessageStatusResponse,\n MessageContentResponse,\n CancelEmailParams,\n CancelEmailResponse,\n RequestOverrides,\n} from '../types';\n\nexport class EmailResource {\n constructor(private http: HttpClient) {}\n\n async send(params: SendEmailParams, overrides?: RequestOverrides): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>('/v1/email/send', params, overrides?.apiKey);\n }\n\n /**\n * Send to many recipients at once.\n *\n * Three shapes, discriminated by what you pass:\n * - `emails[]` with a full `htmlBody` each — the original behaviour, unchanged.\n * - `emails[]` + a shared `htmlBody` + per-recipient `variables` — MAIL MERGE.\n * The template crosses the wire once instead of once per recipient.\n * - `listId` (+ `mapping`) — a saved contact list, with NO recipient cap. The\n * server materializes the recipients in the background and returns a job id.\n *\n * OVERLOADED rather than returning a union, so existing calls keep resolving to\n * `BulkEmailResponse` exactly as before. A bare union would have made\n * `res.recipientCount` a compile error for every caller that upgraded.\n */\n async bulk(params: BulkEmailParams & { listId: string }, overrides?: RequestOverrides): Promise<ListSendResponse>;\n async bulk(params: BulkEmailParams, overrides?: RequestOverrides): Promise<BulkEmailResponse>;\n async bulk(params: BulkEmailParams, overrides?: RequestOverrides): Promise<BulkEmailResponse | ListSendResponse> {\n return this.http.post<BulkEmailResponse | ListSendResponse>('/v1/email/bulk', params, overrides?.apiKey);\n }\n\n async status(jobId: string, overrides?: RequestOverrides): Promise<JobStatusResponse> {\n return this.http.get<JobStatusResponse>(`/v1/email/status/${encodeURIComponent(jobId)}`, undefined, overrides?.apiKey);\n }\n\n /**\n * Look up the current status of a single message by its `messageId` — the ID\n * returned from `send()`/`bulk()` and included in webhook payloads. Useful for\n * reconciling a message whose webhook was missed.\n *\n * Accepts **only** a message ID — not a job ID or SES message ID. The message\n * must belong to the tenant the API key is scoped to; otherwise a `NotFoundError`\n * is thrown. The status reflects the latest event recorded by the SES event\n * pipeline.\n */\n async getMessageStatus(messageId: string, overrides?: RequestOverrides): Promise<MessageStatusResponse> {\n return this.http.get<MessageStatusResponse>(`/v1/email/messages/${encodeURIComponent(messageId)}/status`, undefined, overrides?.apiKey);\n }\n\n /**\n * Fetch the content that was sent for a single message by its `messageId` — the\n * subject, envelope and `htmlBody`/`textBody`, exactly as sent (the HTML includes\n * the appended unsubscribe footer). This is the same content the dashboard renders\n * in its \"Preview\", so you can reconstruct or re-display a sent email on your side.\n *\n * Accepts **only** a message ID — not a job ID or SES message ID. The message must\n * belong to the tenant the API key is scoped to; otherwise a `NotFoundError` is\n * thrown. Attachments are not inlined.\n */\n async getMessageContent(messageId: string, overrides?: RequestOverrides): Promise<MessageContentResponse> {\n return this.http.get<MessageContentResponse>(`/v1/email/messages/${encodeURIComponent(messageId)}/content`, undefined, overrides?.apiKey);\n }\n\n /**\n * Cancel all queued/processing emails for a campaign or job.\n * Provide either `campaignId` (cancels all jobs in that campaign) or `jobId` (cancels one job).\n * Already-sent emails cannot be recalled — only recipients still in `queued` or `processing` state are cancelled.\n */\n async cancel(params: CancelEmailParams, overrides?: RequestOverrides): Promise<CancelEmailResponse> {\n if (!params.campaignId && !params.jobId) {\n throw new Error('cancel() requires either campaignId or jobId');\n }\n return this.http.post<CancelEmailResponse>('/v1/email/cancel', params, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateTemplateParams,\n UpdateTemplateParams,\n ListTemplatesParams,\n ListTemplatesResponse,\n Template,\n TemplateResponse,\n TemplateSendParams,\n SendEmailResponse,\n TemplateBulkSendParams,\n TemplateBulkSendResponse,\n ListSendResponse,\n TemplatePreviewParams,\n TemplatePreviewResponse,\n TemplateStatsResponse,\n RequestOverrides,\n} from '../types';\n\nexport class TemplatesResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateTemplateParams, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>('/v1/email-templates', params, overrides?.apiKey);\n }\n\n async list(params?: ListTemplatesParams, overrides?: RequestOverrides): Promise<ListTemplatesResponse> {\n return this.http.get<ListTemplatesResponse>('/v1/email-templates', params as Record<string, unknown>, overrides?.apiKey);\n }\n\n async *listAll(params?: Omit<ListTemplatesParams, 'page'>, overrides?: RequestOverrides): AsyncGenerator<Template> {\n let page = 1;\n const limit = params?.limit || 20;\n\n while (true) {\n const result = await this.list({ ...params, page, limit }, overrides);\n for (const template of result.templates) {\n yield template;\n }\n if (result.templates.length < limit) break;\n page++;\n }\n }\n\n async get(id: string, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.get<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}`, undefined, overrides?.apiKey);\n }\n\n async update(id: string, params: UpdateTemplateParams, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.patch<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}`, params, overrides?.apiKey);\n }\n\n async delete(id: string, overrides?: RequestOverrides): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(`/v1/email-templates/${encodeURIComponent(id)}`, overrides?.apiKey);\n }\n\n async duplicate(id: string, params?: { name?: string }, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}/duplicate`, params, overrides?.apiKey);\n }\n\n async preview(id: string, params?: TemplatePreviewParams, overrides?: RequestOverrides): Promise<TemplatePreviewResponse> {\n return this.http.post<TemplatePreviewResponse>(`/v1/email-templates/${encodeURIComponent(id)}/preview`, params, overrides?.apiKey);\n }\n\n async send(params: TemplateSendParams, overrides?: RequestOverrides): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>('/v1/email-templates/send', params, overrides?.apiKey);\n }\n\n /**\n * Send a template to many recipients.\n *\n * Pass `recipients[]` (up to 1000) for an inline send, or `listId` (+ `mapping`)\n * to send to a whole saved contact list with no recipient cap — the server\n * expands the list in the background.\n *\n * Overloaded rather than returning a union, so existing calls keep resolving to\n * `TemplateBulkSendResponse` and upgrading the SDK cannot break a build.\n */\n async bulkSend(params: TemplateBulkSendParams & { listId: string }, overrides?: RequestOverrides): Promise<ListSendResponse>;\n async bulkSend(params: TemplateBulkSendParams, overrides?: RequestOverrides): Promise<TemplateBulkSendResponse>;\n async bulkSend(params: TemplateBulkSendParams, overrides?: RequestOverrides): Promise<TemplateBulkSendResponse | ListSendResponse> {\n return this.http.post<TemplateBulkSendResponse | ListSendResponse>('/v1/email-templates/bulk', params, overrides?.apiKey);\n }\n\n async stats(overrides?: RequestOverrides): Promise<TemplateStatsResponse> {\n return this.http.get<TemplateStatsResponse>('/v1/email-templates/stats', undefined, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ListSuppressionsParams,\n ListSuppressionsResponse,\n AddSuppressionParams,\n SuppressionResponse,\n Suppression,\n EmailList,\n SearchSuppressionsParams,\n SearchSuppressionsResponse,\n BulkAddSuppressionsParams,\n BulkAddSuppressionsResponse,\n BulkRemoveSuppressionsParams,\n BulkRemoveSuppressionsResponse,\n RequestOverrides,\n} from '../types';\n\n/**\n * The API takes a comma-separated list on the wire. Arrays are the ergonomic\n * form for callers, so normalize here rather than making every caller join.\n */\nfunction toEmailList(emails: EmailList): string {\n return Array.isArray(emails) ? emails.join(',') : emails;\n}\n\nexport class SuppressionsResource {\n constructor(private http: HttpClient) {}\n\n async list(params?: ListSuppressionsParams, overrides?: RequestOverrides): Promise<ListSuppressionsResponse> {\n return this.http.get<ListSuppressionsResponse>('/v1/tenants/suppressions', params as Record<string, unknown>, overrides?.apiKey);\n }\n\n async *listAll(params?: Omit<ListSuppressionsParams, 'page'>, overrides?: RequestOverrides): AsyncGenerator<Suppression> {\n let page = 1;\n const limit = params?.limit || 50;\n\n while (true) {\n const result = await this.list({ ...params, page, limit }, overrides);\n for (const suppression of result.suppressions) {\n yield suppression;\n }\n if (result.suppressions.length < limit) break;\n page++;\n }\n }\n\n /**\n * Look up specific addresses on the suppression list — exact, case-insensitive,\n * up to 100 per request. Every address is validated server-side before it is\n * queried, so a malformed entry comes back in `rejected` instead of failing the\n * whole call.\n *\n * For substring matching (e.g. every address on a domain), use\n * `list({ search: 'acme.com' })` instead.\n */\n async search(params: SearchSuppressionsParams, overrides?: RequestOverrides): Promise<SearchSuppressionsResponse> {\n return this.http.get<SearchSuppressionsResponse>(\n '/v1/tenants/suppressions/search',\n { emails: toEmailList(params.emails) },\n overrides?.apiKey,\n );\n }\n\n async add(params: AddSuppressionParams, overrides?: RequestOverrides): Promise<SuppressionResponse> {\n return this.http.post<SuppressionResponse>('/v1/tenants/suppressions', params, overrides?.apiKey);\n }\n\n /**\n * Suppress up to 1000 addresses in one request. Valid addresses are added and\n * reported in `added`; ones already on the list come back in `alreadySuppressed`\n * with their existing record untouched; ones that fail validation come back in\n * `rejected` and are never written.\n */\n async bulkAdd(params: BulkAddSuppressionsParams, overrides?: RequestOverrides): Promise<BulkAddSuppressionsResponse> {\n return this.http.post<BulkAddSuppressionsResponse>(\n '/v1/tenants/suppressions/bulk/add',\n { emails: toEmailList(params.emails), reason: params.reason },\n overrides?.apiKey,\n );\n }\n\n /**\n * Unsuppress up to 1000 addresses in one request. Unlike `remove()`, an address\n * that is not on the list is not an error: it is reported in `notFound`, so one\n * bad entry cannot fail the batch.\n */\n async bulkRemove(params: BulkRemoveSuppressionsParams, overrides?: RequestOverrides): Promise<BulkRemoveSuppressionsResponse> {\n return this.http.post<BulkRemoveSuppressionsResponse>(\n '/v1/tenants/suppressions/bulk/remove',\n { emails: toEmailList(params.emails) },\n overrides?.apiKey,\n );\n }\n\n async remove(email: string, overrides?: RequestOverrides): Promise<{ message: string }> {\n return this.http.delete<{ message: string }>(`/v1/tenants/suppressions/${encodeURIComponent(email)}`, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateWebhookParams,\n CreateWebhookResponse,\n UpdateWebhookParams,\n UpdateWebhookResponse,\n ListWebhooksResponse,\n RequestOverrides,\n} from '../types';\n\nexport class WebhooksResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateWebhookParams, overrides?: RequestOverrides): Promise<CreateWebhookResponse> {\n return this.http.post<CreateWebhookResponse>('/v1/tenants/webhooks', params, overrides?.apiKey);\n }\n\n async list(overrides?: RequestOverrides): Promise<ListWebhooksResponse> {\n return this.http.get<ListWebhooksResponse>('/v1/tenants/webhooks', undefined, overrides?.apiKey);\n }\n\n async update(id: string, params: UpdateWebhookParams, overrides?: RequestOverrides): Promise<UpdateWebhookResponse> {\n return this.http.patch<UpdateWebhookResponse>(`/v1/tenants/webhooks/${encodeURIComponent(id)}`, params, overrides?.apiKey);\n }\n\n async delete(id: string, overrides?: RequestOverrides): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(`/v1/tenants/webhooks/${encodeURIComponent(id)}`, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type { DashboardResponse, QuotaResponse, RequestOverrides } from '../types';\n\nexport class DashboardResource {\n constructor(private http: HttpClient) {}\n\n async get(overrides?: RequestOverrides): Promise<DashboardResponse> {\n return this.http.get<DashboardResponse>('/v1/tenants/dashboard', undefined, overrides?.apiKey);\n }\n\n async quota(overrides?: RequestOverrides): Promise<QuotaResponse> {\n return this.http.get<QuotaResponse>('/v1/tenants/quota', undefined, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n GlobalQuotaResponse,\n CheckQuotaResponse,\n RequestOverrides,\n} from '../types';\n\n/**\n * Account-global quota: the shared SES 24h cap across ALL tenants/sources.\n *\n * Sends are NOT gated — `email.send`/`email.bulk` always submit. This is an\n * OPT-IN routing aid: call `check(count)` before a batch to ask whether the\n * shared pool has room and atomically hold it against concurrent callers. An\n * `ok:false` is a normal answer (route that batch to a fallback vendor).\n *\n * `global()` is a cheap point-in-time read; `check()` is the atomic, concurrency-\n * safe primitive that most callers want.\n */\nexport class QuotaResource {\n constructor(private http: HttpClient) {}\n\n /** Read the global quota snapshot (point-in-time). For concurrency safety use `check()`. */\n async global(overrides?: RequestOverrides): Promise<GlobalQuotaResponse> {\n return this.http.get<GlobalQuotaResponse>('/v1/quota/global', undefined, overrides?.apiKey);\n }\n\n /**\n * Opt-in quota check. Atomically holds `count` against the shared pool and\n * returns whether it fit — so two concurrent `check(300)` calls against 500 of\n * headroom can't both succeed. `ok:false` is a normal response (route to a\n * fallback vendor), not an error. The hold auto-expires after `ttlSeconds`;\n * there is no reservationId and nothing to release.\n */\n async check(count: number, overrides?: RequestOverrides): Promise<CheckQuotaResponse> {\n return this.http.post<CheckQuotaResponse>('/v1/quota/check', { count }, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ListCampaignsParams,\n ListCampaignsResponse,\n CampaignAnalyticsParams,\n CampaignAnalytics,\n RequestOverrides,\n} from '../types';\n\nexport class CampaignsResource {\n constructor(private http: HttpClient) {}\n\n /** List the tenant's campaigns with headline send stats. */\n async list(params?: ListCampaignsParams, overrides?: RequestOverrides): Promise<ListCampaignsResponse> {\n return this.http.get<ListCampaignsResponse>(\n '/v1/tenants/campaigns',\n params as Record<string, unknown> | undefined,\n overrides?.apiKey,\n );\n }\n\n /** Full analytics report for one campaign (totals, rates, timeseries, breakdowns). */\n async analytics(\n campaignId: string,\n params?: CampaignAnalyticsParams,\n overrides?: RequestOverrides,\n ): Promise<CampaignAnalytics> {\n return this.http.get<CampaignAnalytics>(\n `/v1/tenants/campaigns/${encodeURIComponent(campaignId)}/analytics`,\n params as Record<string, unknown> | undefined,\n overrides?.apiKey,\n );\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ContactList,\n ContactListDetail,\n CreateContactListParams,\n UpdateContactListParams,\n ListContactListsParams,\n ListContactListsResponse,\n ImportContactsParams,\n ImportContactsResponse,\n ListContactsParams,\n ListContactsResponse,\n AddContactParams,\n UpdateContactParams,\n Contact,\n BulkDeleteContactsParams,\n BulkDeleteContactsResponse,\n ContactListFieldsResponse,\n RecountContactListResponse,\n AcceptedResponse,\n RequestOverrides,\n} from '../types';\n\n/**\n * Contact lists: reusable audiences you can send to without a recipient limit.\n *\n * The per-request cap on `email.bulk` / `templates.bulkSend` exists because those\n * carry their recipients in the request body. A list send carries only a `listId`,\n * and the server expands the list in the background — so there is no cap, and the\n * caller gets one job id to track however large the audience is.\n *\n * ── Address hygiene ──\n * Every imported address is sanitized (display-name unwrapping, `mailto:`,\n * zero-width characters, quotes, case) and then validated with the SAME rules the\n * send path applies. Addresses that fail are STORED with `status: 'invalid'` rather\n * than discarded, so you can list them, export them and fix them. Addresses on your\n * suppression list are stored with the matching status. Only `subscribed` contacts\n * are ever sent to, and bounces, complaints and unsubscribes flow back onto the\n * contact automatically.\n */\nexport class ContactListsResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateContactListParams, overrides?: RequestOverrides): Promise<{ message: string; list: ContactList }> {\n return this.http.post('/v1/contact-lists', params, overrides?.apiKey);\n }\n\n async list(params?: ListContactListsParams, overrides?: RequestOverrides): Promise<ListContactListsResponse> {\n return this.http.get<ListContactListsResponse>('/v1/contact-lists', params as Record<string, unknown>, overrides?.apiKey);\n }\n\n /** Auto-paginating iterator over every contact list, mirroring templates.listAll(). */\n async *listAll(params?: Omit<ListContactListsParams, 'page'>, overrides?: RequestOverrides): AsyncGenerator<ContactList> {\n const limit = params?.limit ?? 100;\n let page = 1;\n for (;;) {\n const result = await this.list({ ...params, page, limit }, overrides);\n for (const item of result.lists) yield item;\n if (result.lists.length < limit) return;\n page += 1;\n }\n }\n\n /** A list plus its per-status breakdown (how many are sendable, invalid, bounced...). */\n async get(listId: string, overrides?: RequestOverrides): Promise<ContactListDetail> {\n return this.http.get<ContactListDetail>(`/v1/contact-lists/${encodeURIComponent(listId)}`, undefined, overrides?.apiKey);\n }\n\n async update(listId: string, params: UpdateContactListParams, overrides?: RequestOverrides): Promise<{ message: string; list: ContactList }> {\n return this.http.patch(`/v1/contact-lists/${encodeURIComponent(listId)}`, params, overrides?.apiKey);\n }\n\n /**\n * Delete a list. Returns 202: the contacts are removed by a background job in\n * chunks, so a multi-million-row list does not block on one enormous transaction.\n * Fails with a conflict while a send is still expanding this list.\n */\n async delete(listId: string, overrides?: RequestOverrides): Promise<AcceptedResponse> {\n return this.http.delete<AcceptedResponse>(`/v1/contact-lists/${encodeURIComponent(listId)}`, overrides?.apiKey);\n }\n\n /**\n * Import a chunk of contacts (max 1000 rows per call).\n *\n * Pass the same `importId` with an incrementing `chunkIndex` for every chunk of\n * one file: that pair makes a retried chunk a no-op instead of a double-insert,\n * so a network failure mid-upload is safe to retry blindly.\n *\n * `onExisting: 'update'` merges attributes into contacts already in the list. It\n * never re-subscribes someone who bounced, complained or opted out.\n */\n async importContacts(listId: string, params: ImportContactsParams, overrides?: RequestOverrides): Promise<ImportContactsResponse> {\n return this.http.post<ImportContactsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/import`, params, overrides?.apiKey,\n );\n }\n\n /**\n * List contacts. KEYSET paginated: pass the previous response's\n * `pagination.nextCursor` as `cursor` to advance. There is no page number,\n * because offset paging degrades badly past a few hundred pages.\n */\n async contacts(listId: string, params?: ListContactsParams, overrides?: RequestOverrides): Promise<ListContactsResponse> {\n return this.http.get<ListContactsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts`, params as Record<string, unknown>, overrides?.apiKey,\n );\n }\n\n /** Auto-paginating iterator over every contact in a list. */\n async *contactsAll(listId: string, params?: Omit<ListContactsParams, 'cursor'>, overrides?: RequestOverrides): AsyncGenerator<Contact> {\n let cursor: string | undefined;\n for (;;) {\n const result = await this.contacts(listId, { ...params, cursor }, overrides);\n for (const contact of result.contacts) yield contact;\n if (!result.pagination.hasMore || !result.pagination.nextCursor) return;\n cursor = result.pagination.nextCursor;\n }\n }\n\n async addContact(listId: string, params: AddContactParams, overrides?: RequestOverrides): Promise<{ message: string; contact: Contact }> {\n return this.http.post(`/v1/contact-lists/${encodeURIComponent(listId)}/contacts`, params, overrides?.apiKey);\n }\n\n /** `attributes` REPLACES the stored object wholesale here; import merges instead. */\n async updateContact(listId: string, contactId: string, params: UpdateContactParams, overrides?: RequestOverrides): Promise<{ message: string; contact: Contact }> {\n return this.http.patch(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/${encodeURIComponent(contactId)}`, params, overrides?.apiKey,\n );\n }\n\n async deleteContact(listId: string, contactId: string, overrides?: RequestOverrides): Promise<void> {\n await this.http.delete(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/${encodeURIComponent(contactId)}`, overrides?.apiKey,\n );\n }\n\n /**\n * Delete many contacts. Pass `contactIds` or `emails` (up to 1000), or a FILTER\n * — `{ status: 'invalid' }` or `{ all: true }` — which is how you clear tens of\n * thousands of dead addresses in one small request. Filtered deletes return 202\n * and run in the background.\n */\n async bulkDeleteContacts(listId: string, params: BulkDeleteContactsParams, overrides?: RequestOverrides): Promise<BulkDeleteContactsResponse> {\n return this.http.post<BulkDeleteContactsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/bulk-delete`, params, overrides?.apiKey,\n );\n }\n\n /**\n * The column names available for send-time variable mapping, with a sample value\n * for each. This is what tells you which `mapping` keys a list will accept.\n */\n async fields(listId: string, options?: { refresh?: boolean }, overrides?: RequestOverrides): Promise<ContactListFieldsResponse> {\n return this.http.get<ContactListFieldsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/fields`,\n options?.refresh ? { refresh: 'true' } : undefined,\n overrides?.apiKey,\n );\n }\n\n /**\n * Re-run validation and re-sync suppression across the whole list. Useful after a\n * bulk suppression import, or to refresh a list that has been sitting. Returns 202.\n */\n async revalidate(listId: string, overrides?: RequestOverrides): Promise<AcceptedResponse> {\n return this.http.post<AcceptedResponse>(`/v1/contact-lists/${encodeURIComponent(listId)}/revalidate`, {}, overrides?.apiKey);\n }\n\n /** Reconcile the denormalized contact count with an exact COUNT. */\n async recount(listId: string, overrides?: RequestOverrides): Promise<RecountContactListResponse> {\n return this.http.post<RecountContactListResponse>(`/v1/contact-lists/${encodeURIComponent(listId)}/recount`, {}, overrides?.apiKey);\n }\n}\n","import { HttpClient } from './http';\nimport { EmailResource } from './resources/email';\nimport { TemplatesResource } from './resources/templates';\nimport { SuppressionsResource } from './resources/suppressions';\nimport { WebhooksResource } from './resources/webhooks';\nimport { DashboardResource } from './resources/dashboard';\nimport { QuotaResource } from './resources/quota';\nimport { CampaignsResource } from './resources/campaigns';\nimport { ContactListsResource } from './resources/contactLists';\nimport type { OutboundConfig, ResolvedConfig } from './types';\n\nconst BASE_URL = 'https://outbound-api.unionstack.in';\n\nexport class Outbound {\n readonly email: EmailResource;\n readonly templates: TemplatesResource;\n readonly suppressions: SuppressionsResource;\n readonly webhooks: WebhooksResource;\n readonly dashboard: DashboardResource;\n readonly quota: QuotaResource;\n readonly campaigns: CampaignsResource;\n readonly contactLists: ContactListsResource;\n\n constructor(config?: OutboundConfig) {\n const resolved: ResolvedConfig = {\n apiKey: config?.apiKey,\n baseUrl: config?.baseUrl || BASE_URL,\n timeout: config?.timeout ?? 30_000,\n maxRetries: config?.maxRetries ?? 3,\n retryDelay: config?.retryDelay ?? 1000,\n };\n\n const http = new HttpClient(resolved);\n\n this.email = new EmailResource(http);\n this.templates = new TemplatesResource(http);\n this.suppressions = new SuppressionsResource(http);\n this.webhooks = new WebhooksResource(http);\n this.dashboard = new DashboardResource(http);\n this.quota = new QuotaResource(http);\n this.campaigns = new CampaignsResource(http);\n this.contactLists = new ContactListsResource(http);\n }\n\n /**\n * Verify a webhook signature using HMAC-SHA256.\n * Use this in your webhook handler to validate incoming requests.\n */\n static verifyWebhookSignature(\n payload: string | Buffer,\n signature: string,\n secret: string,\n ): boolean {\n // Dynamic import to keep browser-compatible at the type level\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const crypto = require('crypto') as typeof import('crypto');\n const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');\n try {\n return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -218,17 +218,6 @@ var EmailResource = class {
|
|
|
218
218
|
async send(params, overrides) {
|
|
219
219
|
return this.http.post("/v1/email/send", params, overrides?.apiKey);
|
|
220
220
|
}
|
|
221
|
-
/**
|
|
222
|
-
* Send to many recipients at once.
|
|
223
|
-
*
|
|
224
|
-
* Three shapes, discriminated by what you pass:
|
|
225
|
-
* - `emails[]` with a full `htmlBody` each — the original behaviour, unchanged.
|
|
226
|
-
* - `emails[]` + a shared `htmlBody` + per-recipient `variables` — MAIL MERGE.
|
|
227
|
-
* The template crosses the wire once instead of once per recipient.
|
|
228
|
-
* - `listId` (+ `mapping`) — a saved contact list, with NO recipient cap. Returns
|
|
229
|
-
* a `ListSendResponse` with `mode: 'list'` and a job id you can poll; the
|
|
230
|
-
* server materializes the recipients in the background.
|
|
231
|
-
*/
|
|
232
221
|
async bulk(params, overrides) {
|
|
233
222
|
return this.http.post("/v1/email/bulk", params, overrides?.apiKey);
|
|
234
223
|
}
|
|
@@ -315,13 +304,6 @@ var TemplatesResource = class {
|
|
|
315
304
|
async send(params, overrides) {
|
|
316
305
|
return this.http.post("/v1/email-templates/send", params, overrides?.apiKey);
|
|
317
306
|
}
|
|
318
|
-
/**
|
|
319
|
-
* Send a template to many recipients.
|
|
320
|
-
*
|
|
321
|
-
* Pass `recipients[]` (up to 1000) for an inline send, or `listId` (+ `mapping`)
|
|
322
|
-
* to send to a whole saved contact list with no recipient cap — the server
|
|
323
|
-
* expands the list in the background and returns `mode: 'list'` with a job id.
|
|
324
|
-
*/
|
|
325
307
|
async bulkSend(params, overrides) {
|
|
326
308
|
return this.http.post("/v1/email-templates/bulk", params, overrides?.apiKey);
|
|
327
309
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/resources/email.ts","../src/resources/templates.ts","../src/resources/suppressions.ts","../src/resources/webhooks.ts","../src/resources/dashboard.ts","../src/resources/quota.ts","../src/resources/campaigns.ts","../src/resources/contactLists.ts","../src/client.ts"],"sourcesContent":["export class OutboundError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly details?: unknown,\n public readonly requestId?: string,\n ) {\n super(message);\n this.name = 'OutboundError';\n }\n}\n\nexport class BadRequestError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 400, details, requestId);\n this.name = 'BadRequestError';\n }\n}\n\nexport class AuthenticationError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 401, details, requestId);\n this.name = 'AuthenticationError';\n }\n}\n\nexport class ForbiddenError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 403, details, requestId);\n this.name = 'ForbiddenError';\n }\n}\n\nexport class NotFoundError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 404, details, requestId);\n this.name = 'NotFoundError';\n }\n}\n\nexport class ConflictError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 409, details, requestId);\n this.name = 'ConflictError';\n }\n}\n\nexport class RateLimitError extends OutboundError {\n public readonly retryAfter?: number;\n\n constructor(message: string, retryAfter?: number, details?: unknown, requestId?: string) {\n super(message, 429, details, requestId);\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\nexport class ServerError extends OutboundError {\n constructor(message: string, statusCode: number = 500, details?: unknown, requestId?: string) {\n super(message, statusCode, details, requestId);\n this.name = 'ServerError';\n }\n}\n\nexport class TimeoutError extends OutboundError {\n constructor(message: string = 'Request timed out') {\n super(message, 0);\n this.name = 'TimeoutError';\n }\n}\n\nexport class NetworkError extends OutboundError {\n constructor(message: string = 'Network request failed') {\n super(message, 0);\n this.name = 'NetworkError';\n }\n}\n","import type { ResolvedConfig } from './types';\nimport {\n OutboundError,\n BadRequestError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n RateLimitError,\n ServerError,\n TimeoutError,\n NetworkError,\n} from './errors';\n\nexport interface RequestOptions {\n body?: unknown;\n params?: Record<string, unknown>;\n}\n\nexport class HttpClient {\n constructor(private config: ResolvedConfig) {}\n\n async get<T>(path: string, params?: Record<string, unknown>, apiKey?: string): Promise<T> {\n return this.request<T>('GET', path, { params }, apiKey);\n }\n\n async post<T>(path: string, body?: unknown, apiKey?: string): Promise<T> {\n return this.request<T>('POST', path, { body }, apiKey);\n }\n\n async patch<T>(path: string, body?: unknown, apiKey?: string): Promise<T> {\n return this.request<T>('PATCH', path, { body }, apiKey);\n }\n\n async delete<T>(path: string, apiKey?: string): Promise<T> {\n return this.request<T>('DELETE', path, undefined, apiKey);\n }\n\n private resolveApiKey(apiKey?: string): string {\n const key = apiKey || this.config.apiKey;\n if (!key) {\n throw new AuthenticationError(\n 'API key is required. Pass it to the constructor or provide it per method call.',\n );\n }\n return key;\n }\n\n private async request<T>(method: string, path: string, options?: RequestOptions, apiKey?: string): Promise<T> {\n const resolvedKey = this.resolveApiKey(apiKey);\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const url = this.buildUrl(path, options?.params);\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n const response = await fetch(url, {\n method,\n headers: {\n 'X-Api-Key': resolvedKey,\n 'Content-Type': 'application/json',\n },\n body: options?.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const error = await this.parseError(response);\n\n // Only retry on 429 and 5xx\n if (response.status === 429 || response.status >= 500) {\n lastError = error;\n\n if (attempt < this.config.maxRetries) {\n const retryAfter = error instanceof RateLimitError && error.retryAfter\n ? error.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n\n await this.sleep(retryAfter);\n continue;\n }\n }\n\n throw error;\n } catch (err) {\n if (err instanceof OutboundError) {\n // Already a typed error from parseError — check if retryable\n if ((err.statusCode === 429 || err.statusCode >= 500) && attempt < this.config.maxRetries) {\n lastError = err;\n const retryAfter = err instanceof RateLimitError && err.retryAfter\n ? err.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n await this.sleep(retryAfter);\n continue;\n }\n throw err;\n }\n\n if (err instanceof DOMException && err.name === 'AbortError') {\n lastError = new TimeoutError(`Request timed out after ${this.config.timeout}ms`);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n\n lastError = new NetworkError((err as Error).message);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n }\n\n throw lastError || new NetworkError('Request failed after retries');\n }\n\n private buildUrl(path: string, params?: Record<string, unknown>): string {\n const base = this.config.baseUrl.replace(/\\/+$/, '');\n const url = new URL(`${base}${path}`);\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n }\n\n private async parseError(response: Response): Promise<OutboundError> {\n let body: { error?: string; message?: string; details?: unknown } = {};\n const requestId = response.headers.get('x-request-id') || undefined;\n\n try {\n body = (await response.json()) as typeof body;\n } catch {\n // Response may not be JSON\n }\n\n const message = body.error || body.message || `HTTP ${response.status}`;\n const details = body.details;\n\n switch (response.status) {\n case 400:\n return new BadRequestError(message, details, requestId);\n case 401:\n return new AuthenticationError(message, details, requestId);\n case 403:\n return new ForbiddenError(message, details, requestId);\n case 404:\n return new NotFoundError(message, details, requestId);\n case 409:\n return new ConflictError(message, details, requestId);\n case 429: {\n const retryAfter = response.headers.get('retry-after');\n return new RateLimitError(\n message,\n retryAfter ? parseInt(retryAfter, 10) : undefined,\n details,\n requestId,\n );\n }\n default:\n if (response.status >= 500) {\n return new ServerError(message, response.status, details, requestId);\n }\n return new OutboundError(message, response.status, details, requestId);\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n SendEmailParams,\n SendEmailResponse,\n BulkEmailParams,\n BulkEmailResponse,\n ListSendResponse,\n JobStatusResponse,\n MessageStatusResponse,\n MessageContentResponse,\n CancelEmailParams,\n CancelEmailResponse,\n RequestOverrides,\n} from '../types';\n\nexport class EmailResource {\n constructor(private http: HttpClient) {}\n\n async send(params: SendEmailParams, overrides?: RequestOverrides): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>('/v1/email/send', params, overrides?.apiKey);\n }\n\n /**\n * Send to many recipients at once.\n *\n * Three shapes, discriminated by what you pass:\n * - `emails[]` with a full `htmlBody` each — the original behaviour, unchanged.\n * - `emails[]` + a shared `htmlBody` + per-recipient `variables` — MAIL MERGE.\n * The template crosses the wire once instead of once per recipient.\n * - `listId` (+ `mapping`) — a saved contact list, with NO recipient cap. Returns\n * a `ListSendResponse` with `mode: 'list'` and a job id you can poll; the\n * server materializes the recipients in the background.\n */\n async bulk(params: BulkEmailParams, overrides?: RequestOverrides): Promise<BulkEmailResponse | ListSendResponse> {\n return this.http.post<BulkEmailResponse | ListSendResponse>('/v1/email/bulk', params, overrides?.apiKey);\n }\n\n async status(jobId: string, overrides?: RequestOverrides): Promise<JobStatusResponse> {\n return this.http.get<JobStatusResponse>(`/v1/email/status/${encodeURIComponent(jobId)}`, undefined, overrides?.apiKey);\n }\n\n /**\n * Look up the current status of a single message by its `messageId` — the ID\n * returned from `send()`/`bulk()` and included in webhook payloads. Useful for\n * reconciling a message whose webhook was missed.\n *\n * Accepts **only** a message ID — not a job ID or SES message ID. The message\n * must belong to the tenant the API key is scoped to; otherwise a `NotFoundError`\n * is thrown. The status reflects the latest event recorded by the SES event\n * pipeline.\n */\n async getMessageStatus(messageId: string, overrides?: RequestOverrides): Promise<MessageStatusResponse> {\n return this.http.get<MessageStatusResponse>(`/v1/email/messages/${encodeURIComponent(messageId)}/status`, undefined, overrides?.apiKey);\n }\n\n /**\n * Fetch the content that was sent for a single message by its `messageId` — the\n * subject, envelope and `htmlBody`/`textBody`, exactly as sent (the HTML includes\n * the appended unsubscribe footer). This is the same content the dashboard renders\n * in its \"Preview\", so you can reconstruct or re-display a sent email on your side.\n *\n * Accepts **only** a message ID — not a job ID or SES message ID. The message must\n * belong to the tenant the API key is scoped to; otherwise a `NotFoundError` is\n * thrown. Attachments are not inlined.\n */\n async getMessageContent(messageId: string, overrides?: RequestOverrides): Promise<MessageContentResponse> {\n return this.http.get<MessageContentResponse>(`/v1/email/messages/${encodeURIComponent(messageId)}/content`, undefined, overrides?.apiKey);\n }\n\n /**\n * Cancel all queued/processing emails for a campaign or job.\n * Provide either `campaignId` (cancels all jobs in that campaign) or `jobId` (cancels one job).\n * Already-sent emails cannot be recalled — only recipients still in `queued` or `processing` state are cancelled.\n */\n async cancel(params: CancelEmailParams, overrides?: RequestOverrides): Promise<CancelEmailResponse> {\n if (!params.campaignId && !params.jobId) {\n throw new Error('cancel() requires either campaignId or jobId');\n }\n return this.http.post<CancelEmailResponse>('/v1/email/cancel', params, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateTemplateParams,\n UpdateTemplateParams,\n ListTemplatesParams,\n ListTemplatesResponse,\n Template,\n TemplateResponse,\n TemplateSendParams,\n SendEmailResponse,\n TemplateBulkSendParams,\n TemplateBulkSendResponse,\n ListSendResponse,\n TemplatePreviewParams,\n TemplatePreviewResponse,\n TemplateStatsResponse,\n RequestOverrides,\n} from '../types';\n\nexport class TemplatesResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateTemplateParams, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>('/v1/email-templates', params, overrides?.apiKey);\n }\n\n async list(params?: ListTemplatesParams, overrides?: RequestOverrides): Promise<ListTemplatesResponse> {\n return this.http.get<ListTemplatesResponse>('/v1/email-templates', params as Record<string, unknown>, overrides?.apiKey);\n }\n\n async *listAll(params?: Omit<ListTemplatesParams, 'page'>, overrides?: RequestOverrides): AsyncGenerator<Template> {\n let page = 1;\n const limit = params?.limit || 20;\n\n while (true) {\n const result = await this.list({ ...params, page, limit }, overrides);\n for (const template of result.templates) {\n yield template;\n }\n if (result.templates.length < limit) break;\n page++;\n }\n }\n\n async get(id: string, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.get<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}`, undefined, overrides?.apiKey);\n }\n\n async update(id: string, params: UpdateTemplateParams, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.patch<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}`, params, overrides?.apiKey);\n }\n\n async delete(id: string, overrides?: RequestOverrides): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(`/v1/email-templates/${encodeURIComponent(id)}`, overrides?.apiKey);\n }\n\n async duplicate(id: string, params?: { name?: string }, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}/duplicate`, params, overrides?.apiKey);\n }\n\n async preview(id: string, params?: TemplatePreviewParams, overrides?: RequestOverrides): Promise<TemplatePreviewResponse> {\n return this.http.post<TemplatePreviewResponse>(`/v1/email-templates/${encodeURIComponent(id)}/preview`, params, overrides?.apiKey);\n }\n\n async send(params: TemplateSendParams, overrides?: RequestOverrides): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>('/v1/email-templates/send', params, overrides?.apiKey);\n }\n\n /**\n * Send a template to many recipients.\n *\n * Pass `recipients[]` (up to 1000) for an inline send, or `listId` (+ `mapping`)\n * to send to a whole saved contact list with no recipient cap — the server\n * expands the list in the background and returns `mode: 'list'` with a job id.\n */\n async bulkSend(params: TemplateBulkSendParams, overrides?: RequestOverrides): Promise<TemplateBulkSendResponse | ListSendResponse> {\n return this.http.post<TemplateBulkSendResponse | ListSendResponse>('/v1/email-templates/bulk', params, overrides?.apiKey);\n }\n\n async stats(overrides?: RequestOverrides): Promise<TemplateStatsResponse> {\n return this.http.get<TemplateStatsResponse>('/v1/email-templates/stats', undefined, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ListSuppressionsParams,\n ListSuppressionsResponse,\n AddSuppressionParams,\n SuppressionResponse,\n Suppression,\n EmailList,\n SearchSuppressionsParams,\n SearchSuppressionsResponse,\n BulkAddSuppressionsParams,\n BulkAddSuppressionsResponse,\n BulkRemoveSuppressionsParams,\n BulkRemoveSuppressionsResponse,\n RequestOverrides,\n} from '../types';\n\n/**\n * The API takes a comma-separated list on the wire. Arrays are the ergonomic\n * form for callers, so normalize here rather than making every caller join.\n */\nfunction toEmailList(emails: EmailList): string {\n return Array.isArray(emails) ? emails.join(',') : emails;\n}\n\nexport class SuppressionsResource {\n constructor(private http: HttpClient) {}\n\n async list(params?: ListSuppressionsParams, overrides?: RequestOverrides): Promise<ListSuppressionsResponse> {\n return this.http.get<ListSuppressionsResponse>('/v1/tenants/suppressions', params as Record<string, unknown>, overrides?.apiKey);\n }\n\n async *listAll(params?: Omit<ListSuppressionsParams, 'page'>, overrides?: RequestOverrides): AsyncGenerator<Suppression> {\n let page = 1;\n const limit = params?.limit || 50;\n\n while (true) {\n const result = await this.list({ ...params, page, limit }, overrides);\n for (const suppression of result.suppressions) {\n yield suppression;\n }\n if (result.suppressions.length < limit) break;\n page++;\n }\n }\n\n /**\n * Look up specific addresses on the suppression list — exact, case-insensitive,\n * up to 100 per request. Every address is validated server-side before it is\n * queried, so a malformed entry comes back in `rejected` instead of failing the\n * whole call.\n *\n * For substring matching (e.g. every address on a domain), use\n * `list({ search: 'acme.com' })` instead.\n */\n async search(params: SearchSuppressionsParams, overrides?: RequestOverrides): Promise<SearchSuppressionsResponse> {\n return this.http.get<SearchSuppressionsResponse>(\n '/v1/tenants/suppressions/search',\n { emails: toEmailList(params.emails) },\n overrides?.apiKey,\n );\n }\n\n async add(params: AddSuppressionParams, overrides?: RequestOverrides): Promise<SuppressionResponse> {\n return this.http.post<SuppressionResponse>('/v1/tenants/suppressions', params, overrides?.apiKey);\n }\n\n /**\n * Suppress up to 1000 addresses in one request. Valid addresses are added and\n * reported in `added`; ones already on the list come back in `alreadySuppressed`\n * with their existing record untouched; ones that fail validation come back in\n * `rejected` and are never written.\n */\n async bulkAdd(params: BulkAddSuppressionsParams, overrides?: RequestOverrides): Promise<BulkAddSuppressionsResponse> {\n return this.http.post<BulkAddSuppressionsResponse>(\n '/v1/tenants/suppressions/bulk/add',\n { emails: toEmailList(params.emails), reason: params.reason },\n overrides?.apiKey,\n );\n }\n\n /**\n * Unsuppress up to 1000 addresses in one request. Unlike `remove()`, an address\n * that is not on the list is not an error: it is reported in `notFound`, so one\n * bad entry cannot fail the batch.\n */\n async bulkRemove(params: BulkRemoveSuppressionsParams, overrides?: RequestOverrides): Promise<BulkRemoveSuppressionsResponse> {\n return this.http.post<BulkRemoveSuppressionsResponse>(\n '/v1/tenants/suppressions/bulk/remove',\n { emails: toEmailList(params.emails) },\n overrides?.apiKey,\n );\n }\n\n async remove(email: string, overrides?: RequestOverrides): Promise<{ message: string }> {\n return this.http.delete<{ message: string }>(`/v1/tenants/suppressions/${encodeURIComponent(email)}`, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateWebhookParams,\n CreateWebhookResponse,\n UpdateWebhookParams,\n UpdateWebhookResponse,\n ListWebhooksResponse,\n RequestOverrides,\n} from '../types';\n\nexport class WebhooksResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateWebhookParams, overrides?: RequestOverrides): Promise<CreateWebhookResponse> {\n return this.http.post<CreateWebhookResponse>('/v1/tenants/webhooks', params, overrides?.apiKey);\n }\n\n async list(overrides?: RequestOverrides): Promise<ListWebhooksResponse> {\n return this.http.get<ListWebhooksResponse>('/v1/tenants/webhooks', undefined, overrides?.apiKey);\n }\n\n async update(id: string, params: UpdateWebhookParams, overrides?: RequestOverrides): Promise<UpdateWebhookResponse> {\n return this.http.patch<UpdateWebhookResponse>(`/v1/tenants/webhooks/${encodeURIComponent(id)}`, params, overrides?.apiKey);\n }\n\n async delete(id: string, overrides?: RequestOverrides): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(`/v1/tenants/webhooks/${encodeURIComponent(id)}`, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type { DashboardResponse, QuotaResponse, RequestOverrides } from '../types';\n\nexport class DashboardResource {\n constructor(private http: HttpClient) {}\n\n async get(overrides?: RequestOverrides): Promise<DashboardResponse> {\n return this.http.get<DashboardResponse>('/v1/tenants/dashboard', undefined, overrides?.apiKey);\n }\n\n async quota(overrides?: RequestOverrides): Promise<QuotaResponse> {\n return this.http.get<QuotaResponse>('/v1/tenants/quota', undefined, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n GlobalQuotaResponse,\n CheckQuotaResponse,\n RequestOverrides,\n} from '../types';\n\n/**\n * Account-global quota: the shared SES 24h cap across ALL tenants/sources.\n *\n * Sends are NOT gated — `email.send`/`email.bulk` always submit. This is an\n * OPT-IN routing aid: call `check(count)` before a batch to ask whether the\n * shared pool has room and atomically hold it against concurrent callers. An\n * `ok:false` is a normal answer (route that batch to a fallback vendor).\n *\n * `global()` is a cheap point-in-time read; `check()` is the atomic, concurrency-\n * safe primitive that most callers want.\n */\nexport class QuotaResource {\n constructor(private http: HttpClient) {}\n\n /** Read the global quota snapshot (point-in-time). For concurrency safety use `check()`. */\n async global(overrides?: RequestOverrides): Promise<GlobalQuotaResponse> {\n return this.http.get<GlobalQuotaResponse>('/v1/quota/global', undefined, overrides?.apiKey);\n }\n\n /**\n * Opt-in quota check. Atomically holds `count` against the shared pool and\n * returns whether it fit — so two concurrent `check(300)` calls against 500 of\n * headroom can't both succeed. `ok:false` is a normal response (route to a\n * fallback vendor), not an error. The hold auto-expires after `ttlSeconds`;\n * there is no reservationId and nothing to release.\n */\n async check(count: number, overrides?: RequestOverrides): Promise<CheckQuotaResponse> {\n return this.http.post<CheckQuotaResponse>('/v1/quota/check', { count }, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ListCampaignsParams,\n ListCampaignsResponse,\n CampaignAnalyticsParams,\n CampaignAnalytics,\n RequestOverrides,\n} from '../types';\n\nexport class CampaignsResource {\n constructor(private http: HttpClient) {}\n\n /** List the tenant's campaigns with headline send stats. */\n async list(params?: ListCampaignsParams, overrides?: RequestOverrides): Promise<ListCampaignsResponse> {\n return this.http.get<ListCampaignsResponse>(\n '/v1/tenants/campaigns',\n params as Record<string, unknown> | undefined,\n overrides?.apiKey,\n );\n }\n\n /** Full analytics report for one campaign (totals, rates, timeseries, breakdowns). */\n async analytics(\n campaignId: string,\n params?: CampaignAnalyticsParams,\n overrides?: RequestOverrides,\n ): Promise<CampaignAnalytics> {\n return this.http.get<CampaignAnalytics>(\n `/v1/tenants/campaigns/${encodeURIComponent(campaignId)}/analytics`,\n params as Record<string, unknown> | undefined,\n overrides?.apiKey,\n );\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ContactList,\n ContactListDetail,\n CreateContactListParams,\n UpdateContactListParams,\n ListContactListsParams,\n ListContactListsResponse,\n ImportContactsParams,\n ImportContactsResponse,\n ListContactsParams,\n ListContactsResponse,\n AddContactParams,\n UpdateContactParams,\n Contact,\n BulkDeleteContactsParams,\n BulkDeleteContactsResponse,\n ContactListFieldsResponse,\n RecountContactListResponse,\n AcceptedResponse,\n RequestOverrides,\n} from '../types';\n\n/**\n * Contact lists: reusable audiences you can send to without a recipient limit.\n *\n * The per-request cap on `email.bulk` / `templates.bulkSend` exists because those\n * carry their recipients in the request body. A list send carries only a `listId`,\n * and the server expands the list in the background — so there is no cap, and the\n * caller gets one job id to track however large the audience is.\n *\n * ── Address hygiene ──\n * Every imported address is sanitized (display-name unwrapping, `mailto:`,\n * zero-width characters, quotes, case) and then validated with the SAME rules the\n * send path applies. Addresses that fail are STORED with `status: 'invalid'` rather\n * than discarded, so you can list them, export them and fix them. Addresses on your\n * suppression list are stored with the matching status. Only `subscribed` contacts\n * are ever sent to, and bounces, complaints and unsubscribes flow back onto the\n * contact automatically.\n */\nexport class ContactListsResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateContactListParams, overrides?: RequestOverrides): Promise<{ message: string; list: ContactList }> {\n return this.http.post('/v1/contact-lists', params, overrides?.apiKey);\n }\n\n async list(params?: ListContactListsParams, overrides?: RequestOverrides): Promise<ListContactListsResponse> {\n return this.http.get<ListContactListsResponse>('/v1/contact-lists', params as Record<string, unknown>, overrides?.apiKey);\n }\n\n /** Auto-paginating iterator over every contact list, mirroring templates.listAll(). */\n async *listAll(params?: Omit<ListContactListsParams, 'page'>, overrides?: RequestOverrides): AsyncGenerator<ContactList> {\n const limit = params?.limit ?? 100;\n let page = 1;\n for (;;) {\n const result = await this.list({ ...params, page, limit }, overrides);\n for (const item of result.lists) yield item;\n if (result.lists.length < limit) return;\n page += 1;\n }\n }\n\n /** A list plus its per-status breakdown (how many are sendable, invalid, bounced...). */\n async get(listId: string, overrides?: RequestOverrides): Promise<ContactListDetail> {\n return this.http.get<ContactListDetail>(`/v1/contact-lists/${encodeURIComponent(listId)}`, undefined, overrides?.apiKey);\n }\n\n async update(listId: string, params: UpdateContactListParams, overrides?: RequestOverrides): Promise<{ message: string; list: ContactList }> {\n return this.http.patch(`/v1/contact-lists/${encodeURIComponent(listId)}`, params, overrides?.apiKey);\n }\n\n /**\n * Delete a list. Returns 202: the contacts are removed by a background job in\n * chunks, so a multi-million-row list does not block on one enormous transaction.\n * Fails with a conflict while a send is still expanding this list.\n */\n async delete(listId: string, overrides?: RequestOverrides): Promise<AcceptedResponse> {\n return this.http.delete<AcceptedResponse>(`/v1/contact-lists/${encodeURIComponent(listId)}`, overrides?.apiKey);\n }\n\n /**\n * Import a chunk of contacts (max 1000 rows per call).\n *\n * Pass the same `importId` with an incrementing `chunkIndex` for every chunk of\n * one file: that pair makes a retried chunk a no-op instead of a double-insert,\n * so a network failure mid-upload is safe to retry blindly.\n *\n * `onExisting: 'update'` merges attributes into contacts already in the list. It\n * never re-subscribes someone who bounced, complained or opted out.\n */\n async importContacts(listId: string, params: ImportContactsParams, overrides?: RequestOverrides): Promise<ImportContactsResponse> {\n return this.http.post<ImportContactsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/import`, params, overrides?.apiKey,\n );\n }\n\n /**\n * List contacts. KEYSET paginated: pass the previous response's\n * `pagination.nextCursor` as `cursor` to advance. There is no page number,\n * because offset paging degrades badly past a few hundred pages.\n */\n async contacts(listId: string, params?: ListContactsParams, overrides?: RequestOverrides): Promise<ListContactsResponse> {\n return this.http.get<ListContactsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts`, params as Record<string, unknown>, overrides?.apiKey,\n );\n }\n\n /** Auto-paginating iterator over every contact in a list. */\n async *contactsAll(listId: string, params?: Omit<ListContactsParams, 'cursor'>, overrides?: RequestOverrides): AsyncGenerator<Contact> {\n let cursor: string | undefined;\n for (;;) {\n const result = await this.contacts(listId, { ...params, cursor }, overrides);\n for (const contact of result.contacts) yield contact;\n if (!result.pagination.hasMore || !result.pagination.nextCursor) return;\n cursor = result.pagination.nextCursor;\n }\n }\n\n async addContact(listId: string, params: AddContactParams, overrides?: RequestOverrides): Promise<{ message: string; contact: Contact }> {\n return this.http.post(`/v1/contact-lists/${encodeURIComponent(listId)}/contacts`, params, overrides?.apiKey);\n }\n\n /** `attributes` REPLACES the stored object wholesale here; import merges instead. */\n async updateContact(listId: string, contactId: string, params: UpdateContactParams, overrides?: RequestOverrides): Promise<{ message: string; contact: Contact }> {\n return this.http.patch(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/${encodeURIComponent(contactId)}`, params, overrides?.apiKey,\n );\n }\n\n async deleteContact(listId: string, contactId: string, overrides?: RequestOverrides): Promise<void> {\n await this.http.delete(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/${encodeURIComponent(contactId)}`, overrides?.apiKey,\n );\n }\n\n /**\n * Delete many contacts. Pass `contactIds` or `emails` (up to 1000), or a FILTER\n * — `{ status: 'invalid' }` or `{ all: true }` — which is how you clear tens of\n * thousands of dead addresses in one small request. Filtered deletes return 202\n * and run in the background.\n */\n async bulkDeleteContacts(listId: string, params: BulkDeleteContactsParams, overrides?: RequestOverrides): Promise<BulkDeleteContactsResponse> {\n return this.http.post<BulkDeleteContactsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/bulk-delete`, params, overrides?.apiKey,\n );\n }\n\n /**\n * The column names available for send-time variable mapping, with a sample value\n * for each. This is what tells you which `mapping` keys a list will accept.\n */\n async fields(listId: string, options?: { refresh?: boolean }, overrides?: RequestOverrides): Promise<ContactListFieldsResponse> {\n return this.http.get<ContactListFieldsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/fields`,\n options?.refresh ? { refresh: 'true' } : undefined,\n overrides?.apiKey,\n );\n }\n\n /**\n * Re-run validation and re-sync suppression across the whole list. Useful after a\n * bulk suppression import, or to refresh a list that has been sitting. Returns 202.\n */\n async revalidate(listId: string, overrides?: RequestOverrides): Promise<AcceptedResponse> {\n return this.http.post<AcceptedResponse>(`/v1/contact-lists/${encodeURIComponent(listId)}/revalidate`, {}, overrides?.apiKey);\n }\n\n /** Reconcile the denormalized contact count with an exact COUNT. */\n async recount(listId: string, overrides?: RequestOverrides): Promise<RecountContactListResponse> {\n return this.http.post<RecountContactListResponse>(`/v1/contact-lists/${encodeURIComponent(listId)}/recount`, {}, overrides?.apiKey);\n }\n}\n","import { HttpClient } from './http';\nimport { EmailResource } from './resources/email';\nimport { TemplatesResource } from './resources/templates';\nimport { SuppressionsResource } from './resources/suppressions';\nimport { WebhooksResource } from './resources/webhooks';\nimport { DashboardResource } from './resources/dashboard';\nimport { QuotaResource } from './resources/quota';\nimport { CampaignsResource } from './resources/campaigns';\nimport { ContactListsResource } from './resources/contactLists';\nimport type { OutboundConfig, ResolvedConfig } from './types';\n\nconst BASE_URL = 'https://outbound-api.unionstack.in';\n\nexport class Outbound {\n readonly email: EmailResource;\n readonly templates: TemplatesResource;\n readonly suppressions: SuppressionsResource;\n readonly webhooks: WebhooksResource;\n readonly dashboard: DashboardResource;\n readonly quota: QuotaResource;\n readonly campaigns: CampaignsResource;\n readonly contactLists: ContactListsResource;\n\n constructor(config?: OutboundConfig) {\n const resolved: ResolvedConfig = {\n apiKey: config?.apiKey,\n baseUrl: config?.baseUrl || BASE_URL,\n timeout: config?.timeout ?? 30_000,\n maxRetries: config?.maxRetries ?? 3,\n retryDelay: config?.retryDelay ?? 1000,\n };\n\n const http = new HttpClient(resolved);\n\n this.email = new EmailResource(http);\n this.templates = new TemplatesResource(http);\n this.suppressions = new SuppressionsResource(http);\n this.webhooks = new WebhooksResource(http);\n this.dashboard = new DashboardResource(http);\n this.quota = new QuotaResource(http);\n this.campaigns = new CampaignsResource(http);\n this.contactLists = new ContactListsResource(http);\n }\n\n /**\n * Verify a webhook signature using HMAC-SHA256.\n * Use this in your webhook handler to validate incoming requests.\n */\n static verifyWebhookSignature(\n payload: string | Buffer,\n signature: string,\n secret: string,\n ): boolean {\n // Dynamic import to keep browser-compatible at the type level\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const crypto = require('crypto') as typeof import('crypto');\n const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');\n try {\n return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/resources/email.ts","../src/resources/templates.ts","../src/resources/suppressions.ts","../src/resources/webhooks.ts","../src/resources/dashboard.ts","../src/resources/quota.ts","../src/resources/campaigns.ts","../src/resources/contactLists.ts","../src/client.ts"],"sourcesContent":["export class OutboundError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly details?: unknown,\n public readonly requestId?: string,\n ) {\n super(message);\n this.name = 'OutboundError';\n }\n}\n\nexport class BadRequestError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 400, details, requestId);\n this.name = 'BadRequestError';\n }\n}\n\nexport class AuthenticationError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 401, details, requestId);\n this.name = 'AuthenticationError';\n }\n}\n\nexport class ForbiddenError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 403, details, requestId);\n this.name = 'ForbiddenError';\n }\n}\n\nexport class NotFoundError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 404, details, requestId);\n this.name = 'NotFoundError';\n }\n}\n\nexport class ConflictError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 409, details, requestId);\n this.name = 'ConflictError';\n }\n}\n\nexport class RateLimitError extends OutboundError {\n public readonly retryAfter?: number;\n\n constructor(message: string, retryAfter?: number, details?: unknown, requestId?: string) {\n super(message, 429, details, requestId);\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\nexport class ServerError extends OutboundError {\n constructor(message: string, statusCode: number = 500, details?: unknown, requestId?: string) {\n super(message, statusCode, details, requestId);\n this.name = 'ServerError';\n }\n}\n\nexport class TimeoutError extends OutboundError {\n constructor(message: string = 'Request timed out') {\n super(message, 0);\n this.name = 'TimeoutError';\n }\n}\n\nexport class NetworkError extends OutboundError {\n constructor(message: string = 'Network request failed') {\n super(message, 0);\n this.name = 'NetworkError';\n }\n}\n","import type { ResolvedConfig } from './types';\nimport {\n OutboundError,\n BadRequestError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n RateLimitError,\n ServerError,\n TimeoutError,\n NetworkError,\n} from './errors';\n\nexport interface RequestOptions {\n body?: unknown;\n params?: Record<string, unknown>;\n}\n\nexport class HttpClient {\n constructor(private config: ResolvedConfig) {}\n\n async get<T>(path: string, params?: Record<string, unknown>, apiKey?: string): Promise<T> {\n return this.request<T>('GET', path, { params }, apiKey);\n }\n\n async post<T>(path: string, body?: unknown, apiKey?: string): Promise<T> {\n return this.request<T>('POST', path, { body }, apiKey);\n }\n\n async patch<T>(path: string, body?: unknown, apiKey?: string): Promise<T> {\n return this.request<T>('PATCH', path, { body }, apiKey);\n }\n\n async delete<T>(path: string, apiKey?: string): Promise<T> {\n return this.request<T>('DELETE', path, undefined, apiKey);\n }\n\n private resolveApiKey(apiKey?: string): string {\n const key = apiKey || this.config.apiKey;\n if (!key) {\n throw new AuthenticationError(\n 'API key is required. Pass it to the constructor or provide it per method call.',\n );\n }\n return key;\n }\n\n private async request<T>(method: string, path: string, options?: RequestOptions, apiKey?: string): Promise<T> {\n const resolvedKey = this.resolveApiKey(apiKey);\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const url = this.buildUrl(path, options?.params);\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n const response = await fetch(url, {\n method,\n headers: {\n 'X-Api-Key': resolvedKey,\n 'Content-Type': 'application/json',\n },\n body: options?.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const error = await this.parseError(response);\n\n // Only retry on 429 and 5xx\n if (response.status === 429 || response.status >= 500) {\n lastError = error;\n\n if (attempt < this.config.maxRetries) {\n const retryAfter = error instanceof RateLimitError && error.retryAfter\n ? error.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n\n await this.sleep(retryAfter);\n continue;\n }\n }\n\n throw error;\n } catch (err) {\n if (err instanceof OutboundError) {\n // Already a typed error from parseError — check if retryable\n if ((err.statusCode === 429 || err.statusCode >= 500) && attempt < this.config.maxRetries) {\n lastError = err;\n const retryAfter = err instanceof RateLimitError && err.retryAfter\n ? err.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n await this.sleep(retryAfter);\n continue;\n }\n throw err;\n }\n\n if (err instanceof DOMException && err.name === 'AbortError') {\n lastError = new TimeoutError(`Request timed out after ${this.config.timeout}ms`);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n\n lastError = new NetworkError((err as Error).message);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n }\n\n throw lastError || new NetworkError('Request failed after retries');\n }\n\n private buildUrl(path: string, params?: Record<string, unknown>): string {\n const base = this.config.baseUrl.replace(/\\/+$/, '');\n const url = new URL(`${base}${path}`);\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n }\n\n private async parseError(response: Response): Promise<OutboundError> {\n let body: { error?: string; message?: string; details?: unknown } = {};\n const requestId = response.headers.get('x-request-id') || undefined;\n\n try {\n body = (await response.json()) as typeof body;\n } catch {\n // Response may not be JSON\n }\n\n const message = body.error || body.message || `HTTP ${response.status}`;\n const details = body.details;\n\n switch (response.status) {\n case 400:\n return new BadRequestError(message, details, requestId);\n case 401:\n return new AuthenticationError(message, details, requestId);\n case 403:\n return new ForbiddenError(message, details, requestId);\n case 404:\n return new NotFoundError(message, details, requestId);\n case 409:\n return new ConflictError(message, details, requestId);\n case 429: {\n const retryAfter = response.headers.get('retry-after');\n return new RateLimitError(\n message,\n retryAfter ? parseInt(retryAfter, 10) : undefined,\n details,\n requestId,\n );\n }\n default:\n if (response.status >= 500) {\n return new ServerError(message, response.status, details, requestId);\n }\n return new OutboundError(message, response.status, details, requestId);\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n SendEmailParams,\n SendEmailResponse,\n BulkEmailParams,\n BulkEmailResponse,\n ListSendResponse,\n JobStatusResponse,\n MessageStatusResponse,\n MessageContentResponse,\n CancelEmailParams,\n CancelEmailResponse,\n RequestOverrides,\n} from '../types';\n\nexport class EmailResource {\n constructor(private http: HttpClient) {}\n\n async send(params: SendEmailParams, overrides?: RequestOverrides): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>('/v1/email/send', params, overrides?.apiKey);\n }\n\n /**\n * Send to many recipients at once.\n *\n * Three shapes, discriminated by what you pass:\n * - `emails[]` with a full `htmlBody` each — the original behaviour, unchanged.\n * - `emails[]` + a shared `htmlBody` + per-recipient `variables` — MAIL MERGE.\n * The template crosses the wire once instead of once per recipient.\n * - `listId` (+ `mapping`) — a saved contact list, with NO recipient cap. The\n * server materializes the recipients in the background and returns a job id.\n *\n * OVERLOADED rather than returning a union, so existing calls keep resolving to\n * `BulkEmailResponse` exactly as before. A bare union would have made\n * `res.recipientCount` a compile error for every caller that upgraded.\n */\n async bulk(params: BulkEmailParams & { listId: string }, overrides?: RequestOverrides): Promise<ListSendResponse>;\n async bulk(params: BulkEmailParams, overrides?: RequestOverrides): Promise<BulkEmailResponse>;\n async bulk(params: BulkEmailParams, overrides?: RequestOverrides): Promise<BulkEmailResponse | ListSendResponse> {\n return this.http.post<BulkEmailResponse | ListSendResponse>('/v1/email/bulk', params, overrides?.apiKey);\n }\n\n async status(jobId: string, overrides?: RequestOverrides): Promise<JobStatusResponse> {\n return this.http.get<JobStatusResponse>(`/v1/email/status/${encodeURIComponent(jobId)}`, undefined, overrides?.apiKey);\n }\n\n /**\n * Look up the current status of a single message by its `messageId` — the ID\n * returned from `send()`/`bulk()` and included in webhook payloads. Useful for\n * reconciling a message whose webhook was missed.\n *\n * Accepts **only** a message ID — not a job ID or SES message ID. The message\n * must belong to the tenant the API key is scoped to; otherwise a `NotFoundError`\n * is thrown. The status reflects the latest event recorded by the SES event\n * pipeline.\n */\n async getMessageStatus(messageId: string, overrides?: RequestOverrides): Promise<MessageStatusResponse> {\n return this.http.get<MessageStatusResponse>(`/v1/email/messages/${encodeURIComponent(messageId)}/status`, undefined, overrides?.apiKey);\n }\n\n /**\n * Fetch the content that was sent for a single message by its `messageId` — the\n * subject, envelope and `htmlBody`/`textBody`, exactly as sent (the HTML includes\n * the appended unsubscribe footer). This is the same content the dashboard renders\n * in its \"Preview\", so you can reconstruct or re-display a sent email on your side.\n *\n * Accepts **only** a message ID — not a job ID or SES message ID. The message must\n * belong to the tenant the API key is scoped to; otherwise a `NotFoundError` is\n * thrown. Attachments are not inlined.\n */\n async getMessageContent(messageId: string, overrides?: RequestOverrides): Promise<MessageContentResponse> {\n return this.http.get<MessageContentResponse>(`/v1/email/messages/${encodeURIComponent(messageId)}/content`, undefined, overrides?.apiKey);\n }\n\n /**\n * Cancel all queued/processing emails for a campaign or job.\n * Provide either `campaignId` (cancels all jobs in that campaign) or `jobId` (cancels one job).\n * Already-sent emails cannot be recalled — only recipients still in `queued` or `processing` state are cancelled.\n */\n async cancel(params: CancelEmailParams, overrides?: RequestOverrides): Promise<CancelEmailResponse> {\n if (!params.campaignId && !params.jobId) {\n throw new Error('cancel() requires either campaignId or jobId');\n }\n return this.http.post<CancelEmailResponse>('/v1/email/cancel', params, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateTemplateParams,\n UpdateTemplateParams,\n ListTemplatesParams,\n ListTemplatesResponse,\n Template,\n TemplateResponse,\n TemplateSendParams,\n SendEmailResponse,\n TemplateBulkSendParams,\n TemplateBulkSendResponse,\n ListSendResponse,\n TemplatePreviewParams,\n TemplatePreviewResponse,\n TemplateStatsResponse,\n RequestOverrides,\n} from '../types';\n\nexport class TemplatesResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateTemplateParams, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>('/v1/email-templates', params, overrides?.apiKey);\n }\n\n async list(params?: ListTemplatesParams, overrides?: RequestOverrides): Promise<ListTemplatesResponse> {\n return this.http.get<ListTemplatesResponse>('/v1/email-templates', params as Record<string, unknown>, overrides?.apiKey);\n }\n\n async *listAll(params?: Omit<ListTemplatesParams, 'page'>, overrides?: RequestOverrides): AsyncGenerator<Template> {\n let page = 1;\n const limit = params?.limit || 20;\n\n while (true) {\n const result = await this.list({ ...params, page, limit }, overrides);\n for (const template of result.templates) {\n yield template;\n }\n if (result.templates.length < limit) break;\n page++;\n }\n }\n\n async get(id: string, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.get<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}`, undefined, overrides?.apiKey);\n }\n\n async update(id: string, params: UpdateTemplateParams, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.patch<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}`, params, overrides?.apiKey);\n }\n\n async delete(id: string, overrides?: RequestOverrides): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(`/v1/email-templates/${encodeURIComponent(id)}`, overrides?.apiKey);\n }\n\n async duplicate(id: string, params?: { name?: string }, overrides?: RequestOverrides): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}/duplicate`, params, overrides?.apiKey);\n }\n\n async preview(id: string, params?: TemplatePreviewParams, overrides?: RequestOverrides): Promise<TemplatePreviewResponse> {\n return this.http.post<TemplatePreviewResponse>(`/v1/email-templates/${encodeURIComponent(id)}/preview`, params, overrides?.apiKey);\n }\n\n async send(params: TemplateSendParams, overrides?: RequestOverrides): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>('/v1/email-templates/send', params, overrides?.apiKey);\n }\n\n /**\n * Send a template to many recipients.\n *\n * Pass `recipients[]` (up to 1000) for an inline send, or `listId` (+ `mapping`)\n * to send to a whole saved contact list with no recipient cap — the server\n * expands the list in the background.\n *\n * Overloaded rather than returning a union, so existing calls keep resolving to\n * `TemplateBulkSendResponse` and upgrading the SDK cannot break a build.\n */\n async bulkSend(params: TemplateBulkSendParams & { listId: string }, overrides?: RequestOverrides): Promise<ListSendResponse>;\n async bulkSend(params: TemplateBulkSendParams, overrides?: RequestOverrides): Promise<TemplateBulkSendResponse>;\n async bulkSend(params: TemplateBulkSendParams, overrides?: RequestOverrides): Promise<TemplateBulkSendResponse | ListSendResponse> {\n return this.http.post<TemplateBulkSendResponse | ListSendResponse>('/v1/email-templates/bulk', params, overrides?.apiKey);\n }\n\n async stats(overrides?: RequestOverrides): Promise<TemplateStatsResponse> {\n return this.http.get<TemplateStatsResponse>('/v1/email-templates/stats', undefined, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ListSuppressionsParams,\n ListSuppressionsResponse,\n AddSuppressionParams,\n SuppressionResponse,\n Suppression,\n EmailList,\n SearchSuppressionsParams,\n SearchSuppressionsResponse,\n BulkAddSuppressionsParams,\n BulkAddSuppressionsResponse,\n BulkRemoveSuppressionsParams,\n BulkRemoveSuppressionsResponse,\n RequestOverrides,\n} from '../types';\n\n/**\n * The API takes a comma-separated list on the wire. Arrays are the ergonomic\n * form for callers, so normalize here rather than making every caller join.\n */\nfunction toEmailList(emails: EmailList): string {\n return Array.isArray(emails) ? emails.join(',') : emails;\n}\n\nexport class SuppressionsResource {\n constructor(private http: HttpClient) {}\n\n async list(params?: ListSuppressionsParams, overrides?: RequestOverrides): Promise<ListSuppressionsResponse> {\n return this.http.get<ListSuppressionsResponse>('/v1/tenants/suppressions', params as Record<string, unknown>, overrides?.apiKey);\n }\n\n async *listAll(params?: Omit<ListSuppressionsParams, 'page'>, overrides?: RequestOverrides): AsyncGenerator<Suppression> {\n let page = 1;\n const limit = params?.limit || 50;\n\n while (true) {\n const result = await this.list({ ...params, page, limit }, overrides);\n for (const suppression of result.suppressions) {\n yield suppression;\n }\n if (result.suppressions.length < limit) break;\n page++;\n }\n }\n\n /**\n * Look up specific addresses on the suppression list — exact, case-insensitive,\n * up to 100 per request. Every address is validated server-side before it is\n * queried, so a malformed entry comes back in `rejected` instead of failing the\n * whole call.\n *\n * For substring matching (e.g. every address on a domain), use\n * `list({ search: 'acme.com' })` instead.\n */\n async search(params: SearchSuppressionsParams, overrides?: RequestOverrides): Promise<SearchSuppressionsResponse> {\n return this.http.get<SearchSuppressionsResponse>(\n '/v1/tenants/suppressions/search',\n { emails: toEmailList(params.emails) },\n overrides?.apiKey,\n );\n }\n\n async add(params: AddSuppressionParams, overrides?: RequestOverrides): Promise<SuppressionResponse> {\n return this.http.post<SuppressionResponse>('/v1/tenants/suppressions', params, overrides?.apiKey);\n }\n\n /**\n * Suppress up to 1000 addresses in one request. Valid addresses are added and\n * reported in `added`; ones already on the list come back in `alreadySuppressed`\n * with their existing record untouched; ones that fail validation come back in\n * `rejected` and are never written.\n */\n async bulkAdd(params: BulkAddSuppressionsParams, overrides?: RequestOverrides): Promise<BulkAddSuppressionsResponse> {\n return this.http.post<BulkAddSuppressionsResponse>(\n '/v1/tenants/suppressions/bulk/add',\n { emails: toEmailList(params.emails), reason: params.reason },\n overrides?.apiKey,\n );\n }\n\n /**\n * Unsuppress up to 1000 addresses in one request. Unlike `remove()`, an address\n * that is not on the list is not an error: it is reported in `notFound`, so one\n * bad entry cannot fail the batch.\n */\n async bulkRemove(params: BulkRemoveSuppressionsParams, overrides?: RequestOverrides): Promise<BulkRemoveSuppressionsResponse> {\n return this.http.post<BulkRemoveSuppressionsResponse>(\n '/v1/tenants/suppressions/bulk/remove',\n { emails: toEmailList(params.emails) },\n overrides?.apiKey,\n );\n }\n\n async remove(email: string, overrides?: RequestOverrides): Promise<{ message: string }> {\n return this.http.delete<{ message: string }>(`/v1/tenants/suppressions/${encodeURIComponent(email)}`, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateWebhookParams,\n CreateWebhookResponse,\n UpdateWebhookParams,\n UpdateWebhookResponse,\n ListWebhooksResponse,\n RequestOverrides,\n} from '../types';\n\nexport class WebhooksResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateWebhookParams, overrides?: RequestOverrides): Promise<CreateWebhookResponse> {\n return this.http.post<CreateWebhookResponse>('/v1/tenants/webhooks', params, overrides?.apiKey);\n }\n\n async list(overrides?: RequestOverrides): Promise<ListWebhooksResponse> {\n return this.http.get<ListWebhooksResponse>('/v1/tenants/webhooks', undefined, overrides?.apiKey);\n }\n\n async update(id: string, params: UpdateWebhookParams, overrides?: RequestOverrides): Promise<UpdateWebhookResponse> {\n return this.http.patch<UpdateWebhookResponse>(`/v1/tenants/webhooks/${encodeURIComponent(id)}`, params, overrides?.apiKey);\n }\n\n async delete(id: string, overrides?: RequestOverrides): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(`/v1/tenants/webhooks/${encodeURIComponent(id)}`, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type { DashboardResponse, QuotaResponse, RequestOverrides } from '../types';\n\nexport class DashboardResource {\n constructor(private http: HttpClient) {}\n\n async get(overrides?: RequestOverrides): Promise<DashboardResponse> {\n return this.http.get<DashboardResponse>('/v1/tenants/dashboard', undefined, overrides?.apiKey);\n }\n\n async quota(overrides?: RequestOverrides): Promise<QuotaResponse> {\n return this.http.get<QuotaResponse>('/v1/tenants/quota', undefined, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n GlobalQuotaResponse,\n CheckQuotaResponse,\n RequestOverrides,\n} from '../types';\n\n/**\n * Account-global quota: the shared SES 24h cap across ALL tenants/sources.\n *\n * Sends are NOT gated — `email.send`/`email.bulk` always submit. This is an\n * OPT-IN routing aid: call `check(count)` before a batch to ask whether the\n * shared pool has room and atomically hold it against concurrent callers. An\n * `ok:false` is a normal answer (route that batch to a fallback vendor).\n *\n * `global()` is a cheap point-in-time read; `check()` is the atomic, concurrency-\n * safe primitive that most callers want.\n */\nexport class QuotaResource {\n constructor(private http: HttpClient) {}\n\n /** Read the global quota snapshot (point-in-time). For concurrency safety use `check()`. */\n async global(overrides?: RequestOverrides): Promise<GlobalQuotaResponse> {\n return this.http.get<GlobalQuotaResponse>('/v1/quota/global', undefined, overrides?.apiKey);\n }\n\n /**\n * Opt-in quota check. Atomically holds `count` against the shared pool and\n * returns whether it fit — so two concurrent `check(300)` calls against 500 of\n * headroom can't both succeed. `ok:false` is a normal response (route to a\n * fallback vendor), not an error. The hold auto-expires after `ttlSeconds`;\n * there is no reservationId and nothing to release.\n */\n async check(count: number, overrides?: RequestOverrides): Promise<CheckQuotaResponse> {\n return this.http.post<CheckQuotaResponse>('/v1/quota/check', { count }, overrides?.apiKey);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ListCampaignsParams,\n ListCampaignsResponse,\n CampaignAnalyticsParams,\n CampaignAnalytics,\n RequestOverrides,\n} from '../types';\n\nexport class CampaignsResource {\n constructor(private http: HttpClient) {}\n\n /** List the tenant's campaigns with headline send stats. */\n async list(params?: ListCampaignsParams, overrides?: RequestOverrides): Promise<ListCampaignsResponse> {\n return this.http.get<ListCampaignsResponse>(\n '/v1/tenants/campaigns',\n params as Record<string, unknown> | undefined,\n overrides?.apiKey,\n );\n }\n\n /** Full analytics report for one campaign (totals, rates, timeseries, breakdowns). */\n async analytics(\n campaignId: string,\n params?: CampaignAnalyticsParams,\n overrides?: RequestOverrides,\n ): Promise<CampaignAnalytics> {\n return this.http.get<CampaignAnalytics>(\n `/v1/tenants/campaigns/${encodeURIComponent(campaignId)}/analytics`,\n params as Record<string, unknown> | undefined,\n overrides?.apiKey,\n );\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ContactList,\n ContactListDetail,\n CreateContactListParams,\n UpdateContactListParams,\n ListContactListsParams,\n ListContactListsResponse,\n ImportContactsParams,\n ImportContactsResponse,\n ListContactsParams,\n ListContactsResponse,\n AddContactParams,\n UpdateContactParams,\n Contact,\n BulkDeleteContactsParams,\n BulkDeleteContactsResponse,\n ContactListFieldsResponse,\n RecountContactListResponse,\n AcceptedResponse,\n RequestOverrides,\n} from '../types';\n\n/**\n * Contact lists: reusable audiences you can send to without a recipient limit.\n *\n * The per-request cap on `email.bulk` / `templates.bulkSend` exists because those\n * carry their recipients in the request body. A list send carries only a `listId`,\n * and the server expands the list in the background — so there is no cap, and the\n * caller gets one job id to track however large the audience is.\n *\n * ── Address hygiene ──\n * Every imported address is sanitized (display-name unwrapping, `mailto:`,\n * zero-width characters, quotes, case) and then validated with the SAME rules the\n * send path applies. Addresses that fail are STORED with `status: 'invalid'` rather\n * than discarded, so you can list them, export them and fix them. Addresses on your\n * suppression list are stored with the matching status. Only `subscribed` contacts\n * are ever sent to, and bounces, complaints and unsubscribes flow back onto the\n * contact automatically.\n */\nexport class ContactListsResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateContactListParams, overrides?: RequestOverrides): Promise<{ message: string; list: ContactList }> {\n return this.http.post('/v1/contact-lists', params, overrides?.apiKey);\n }\n\n async list(params?: ListContactListsParams, overrides?: RequestOverrides): Promise<ListContactListsResponse> {\n return this.http.get<ListContactListsResponse>('/v1/contact-lists', params as Record<string, unknown>, overrides?.apiKey);\n }\n\n /** Auto-paginating iterator over every contact list, mirroring templates.listAll(). */\n async *listAll(params?: Omit<ListContactListsParams, 'page'>, overrides?: RequestOverrides): AsyncGenerator<ContactList> {\n const limit = params?.limit ?? 100;\n let page = 1;\n for (;;) {\n const result = await this.list({ ...params, page, limit }, overrides);\n for (const item of result.lists) yield item;\n if (result.lists.length < limit) return;\n page += 1;\n }\n }\n\n /** A list plus its per-status breakdown (how many are sendable, invalid, bounced...). */\n async get(listId: string, overrides?: RequestOverrides): Promise<ContactListDetail> {\n return this.http.get<ContactListDetail>(`/v1/contact-lists/${encodeURIComponent(listId)}`, undefined, overrides?.apiKey);\n }\n\n async update(listId: string, params: UpdateContactListParams, overrides?: RequestOverrides): Promise<{ message: string; list: ContactList }> {\n return this.http.patch(`/v1/contact-lists/${encodeURIComponent(listId)}`, params, overrides?.apiKey);\n }\n\n /**\n * Delete a list. Returns 202: the contacts are removed by a background job in\n * chunks, so a multi-million-row list does not block on one enormous transaction.\n * Fails with a conflict while a send is still expanding this list.\n */\n async delete(listId: string, overrides?: RequestOverrides): Promise<AcceptedResponse> {\n return this.http.delete<AcceptedResponse>(`/v1/contact-lists/${encodeURIComponent(listId)}`, overrides?.apiKey);\n }\n\n /**\n * Import a chunk of contacts (max 1000 rows per call).\n *\n * Pass the same `importId` with an incrementing `chunkIndex` for every chunk of\n * one file: that pair makes a retried chunk a no-op instead of a double-insert,\n * so a network failure mid-upload is safe to retry blindly.\n *\n * `onExisting: 'update'` merges attributes into contacts already in the list. It\n * never re-subscribes someone who bounced, complained or opted out.\n */\n async importContacts(listId: string, params: ImportContactsParams, overrides?: RequestOverrides): Promise<ImportContactsResponse> {\n return this.http.post<ImportContactsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/import`, params, overrides?.apiKey,\n );\n }\n\n /**\n * List contacts. KEYSET paginated: pass the previous response's\n * `pagination.nextCursor` as `cursor` to advance. There is no page number,\n * because offset paging degrades badly past a few hundred pages.\n */\n async contacts(listId: string, params?: ListContactsParams, overrides?: RequestOverrides): Promise<ListContactsResponse> {\n return this.http.get<ListContactsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts`, params as Record<string, unknown>, overrides?.apiKey,\n );\n }\n\n /** Auto-paginating iterator over every contact in a list. */\n async *contactsAll(listId: string, params?: Omit<ListContactsParams, 'cursor'>, overrides?: RequestOverrides): AsyncGenerator<Contact> {\n let cursor: string | undefined;\n for (;;) {\n const result = await this.contacts(listId, { ...params, cursor }, overrides);\n for (const contact of result.contacts) yield contact;\n if (!result.pagination.hasMore || !result.pagination.nextCursor) return;\n cursor = result.pagination.nextCursor;\n }\n }\n\n async addContact(listId: string, params: AddContactParams, overrides?: RequestOverrides): Promise<{ message: string; contact: Contact }> {\n return this.http.post(`/v1/contact-lists/${encodeURIComponent(listId)}/contacts`, params, overrides?.apiKey);\n }\n\n /** `attributes` REPLACES the stored object wholesale here; import merges instead. */\n async updateContact(listId: string, contactId: string, params: UpdateContactParams, overrides?: RequestOverrides): Promise<{ message: string; contact: Contact }> {\n return this.http.patch(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/${encodeURIComponent(contactId)}`, params, overrides?.apiKey,\n );\n }\n\n async deleteContact(listId: string, contactId: string, overrides?: RequestOverrides): Promise<void> {\n await this.http.delete(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/${encodeURIComponent(contactId)}`, overrides?.apiKey,\n );\n }\n\n /**\n * Delete many contacts. Pass `contactIds` or `emails` (up to 1000), or a FILTER\n * — `{ status: 'invalid' }` or `{ all: true }` — which is how you clear tens of\n * thousands of dead addresses in one small request. Filtered deletes return 202\n * and run in the background.\n */\n async bulkDeleteContacts(listId: string, params: BulkDeleteContactsParams, overrides?: RequestOverrides): Promise<BulkDeleteContactsResponse> {\n return this.http.post<BulkDeleteContactsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/contacts/bulk-delete`, params, overrides?.apiKey,\n );\n }\n\n /**\n * The column names available for send-time variable mapping, with a sample value\n * for each. This is what tells you which `mapping` keys a list will accept.\n */\n async fields(listId: string, options?: { refresh?: boolean }, overrides?: RequestOverrides): Promise<ContactListFieldsResponse> {\n return this.http.get<ContactListFieldsResponse>(\n `/v1/contact-lists/${encodeURIComponent(listId)}/fields`,\n options?.refresh ? { refresh: 'true' } : undefined,\n overrides?.apiKey,\n );\n }\n\n /**\n * Re-run validation and re-sync suppression across the whole list. Useful after a\n * bulk suppression import, or to refresh a list that has been sitting. Returns 202.\n */\n async revalidate(listId: string, overrides?: RequestOverrides): Promise<AcceptedResponse> {\n return this.http.post<AcceptedResponse>(`/v1/contact-lists/${encodeURIComponent(listId)}/revalidate`, {}, overrides?.apiKey);\n }\n\n /** Reconcile the denormalized contact count with an exact COUNT. */\n async recount(listId: string, overrides?: RequestOverrides): Promise<RecountContactListResponse> {\n return this.http.post<RecountContactListResponse>(`/v1/contact-lists/${encodeURIComponent(listId)}/recount`, {}, overrides?.apiKey);\n }\n}\n","import { HttpClient } from './http';\nimport { EmailResource } from './resources/email';\nimport { TemplatesResource } from './resources/templates';\nimport { SuppressionsResource } from './resources/suppressions';\nimport { WebhooksResource } from './resources/webhooks';\nimport { DashboardResource } from './resources/dashboard';\nimport { QuotaResource } from './resources/quota';\nimport { CampaignsResource } from './resources/campaigns';\nimport { ContactListsResource } from './resources/contactLists';\nimport type { OutboundConfig, ResolvedConfig } from './types';\n\nconst BASE_URL = 'https://outbound-api.unionstack.in';\n\nexport class Outbound {\n readonly email: EmailResource;\n readonly templates: TemplatesResource;\n readonly suppressions: SuppressionsResource;\n readonly webhooks: WebhooksResource;\n readonly dashboard: DashboardResource;\n readonly quota: QuotaResource;\n readonly campaigns: CampaignsResource;\n readonly contactLists: ContactListsResource;\n\n constructor(config?: OutboundConfig) {\n const resolved: ResolvedConfig = {\n apiKey: config?.apiKey,\n baseUrl: config?.baseUrl || BASE_URL,\n timeout: config?.timeout ?? 30_000,\n maxRetries: config?.maxRetries ?? 3,\n retryDelay: config?.retryDelay ?? 1000,\n };\n\n const http = new HttpClient(resolved);\n\n this.email = new EmailResource(http);\n this.templates = new TemplatesResource(http);\n this.suppressions = new SuppressionsResource(http);\n this.webhooks = new WebhooksResource(http);\n this.dashboard = new DashboardResource(http);\n this.quota = new QuotaResource(http);\n this.campaigns = new CampaignsResource(http);\n this.contactLists = new ContactListsResource(http);\n }\n\n /**\n * Verify a webhook signature using HMAC-SHA256.\n * Use this in your webhook handler to validate incoming requests.\n */\n static verifyWebhookSignature(\n payload: string | Buffer,\n signature: string,\n secret: string,\n ): boolean {\n // Dynamic import to keep browser-compatible at the type level\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const crypto = require('crypto') as typeof import('crypto');\n const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');\n try {\n return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));\n } catch {\n return false;\n }\n }\n}\n"],"mappings":";;;;;;;;AAAO,IAAM,gBAAN,cAA4B,MAAM;AAAA,EACvC,YACE,SACgB,YACA,SACA,WAChB;AACA,UAAM,OAAO;AAJG;AACA;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,kBAAN,cAA8B,cAAc;AAAA,EACjD,YAAY,SAAiB,SAAmB,WAAoB;AAClE,UAAM,SAAS,KAAK,SAAS,SAAS;AACtC,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,sBAAN,cAAkC,cAAc;AAAA,EACrD,YAAY,SAAiB,SAAmB,WAAoB;AAClE,UAAM,SAAS,KAAK,SAAS,SAAS;AACtC,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,iBAAN,cAA6B,cAAc;AAAA,EAChD,YAAY,SAAiB,SAAmB,WAAoB;AAClE,UAAM,SAAS,KAAK,SAAS,SAAS;AACtC,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,gBAAN,cAA4B,cAAc;AAAA,EAC/C,YAAY,SAAiB,SAAmB,WAAoB;AAClE,UAAM,SAAS,KAAK,SAAS,SAAS;AACtC,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,gBAAN,cAA4B,cAAc;AAAA,EAC/C,YAAY,SAAiB,SAAmB,WAAoB;AAClE,UAAM,SAAS,KAAK,SAAS,SAAS;AACtC,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,iBAAN,cAA6B,cAAc;AAAA,EAChC;AAAA,EAEhB,YAAY,SAAiB,YAAqB,SAAmB,WAAoB;AACvF,UAAM,SAAS,KAAK,SAAS,SAAS;AACtC,SAAK,OAAO;AACZ,SAAK,aAAa;AAAA,EACpB;AACF;AAEO,IAAM,cAAN,cAA0B,cAAc;AAAA,EAC7C,YAAY,SAAiB,aAAqB,KAAK,SAAmB,WAAoB;AAC5F,UAAM,SAAS,YAAY,SAAS,SAAS;AAC7C,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,eAAN,cAA2B,cAAc;AAAA,EAC9C,YAAY,UAAkB,qBAAqB;AACjD,UAAM,SAAS,CAAC;AAChB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,eAAN,cAA2B,cAAc;AAAA,EAC9C,YAAY,UAAkB,0BAA0B;AACtD,UAAM,SAAS,CAAC;AAChB,SAAK,OAAO;AAAA,EACd;AACF;;;ACzDO,IAAM,aAAN,MAAiB;AAAA,EACtB,YAAoB,QAAwB;AAAxB;AAAA,EAAyB;AAAA,EAE7C,MAAM,IAAO,MAAc,QAAkC,QAA6B;AACxF,WAAO,KAAK,QAAW,OAAO,MAAM,EAAE,OAAO,GAAG,MAAM;AAAA,EACxD;AAAA,EAEA,MAAM,KAAQ,MAAc,MAAgB,QAA6B;AACvE,WAAO,KAAK,QAAW,QAAQ,MAAM,EAAE,KAAK,GAAG,MAAM;AAAA,EACvD;AAAA,EAEA,MAAM,MAAS,MAAc,MAAgB,QAA6B;AACxE,WAAO,KAAK,QAAW,SAAS,MAAM,EAAE,KAAK,GAAG,MAAM;AAAA,EACxD;AAAA,EAEA,MAAM,OAAU,MAAc,QAA6B;AACzD,WAAO,KAAK,QAAW,UAAU,MAAM,QAAW,MAAM;AAAA,EAC1D;AAAA,EAEQ,cAAc,QAAyB;AAC7C,UAAM,MAAM,UAAU,KAAK,OAAO;AAClC,QAAI,CAAC,KAAK;AACR,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,QAAW,QAAgB,MAAc,SAA0B,QAA6B;AAC5G,UAAM,cAAc,KAAK,cAAc,MAAM;AAC7C,QAAI;AAEJ,aAAS,UAAU,GAAG,WAAW,KAAK,OAAO,YAAY,WAAW;AAClE,UAAI;AACF,cAAM,MAAM,KAAK,SAAS,MAAM,SAAS,MAAM;AAC/C,cAAM,aAAa,IAAI,gBAAgB;AACvC,cAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,OAAO,OAAO;AAE1E,cAAM,WAAW,MAAM,MAAM,KAAK;AAAA,UAChC;AAAA,UACA,SAAS;AAAA,YACP,aAAa;AAAA,YACb,gBAAgB;AAAA,UAClB;AAAA,UACA,MAAM,SAAS,OAAO,KAAK,UAAU,QAAQ,IAAI,IAAI;AAAA,UACrD,QAAQ,WAAW;AAAA,QACrB,CAAC;AAED,qBAAa,SAAS;AAEtB,YAAI,SAAS,IAAI;AACf,iBAAQ,MAAM,SAAS,KAAK;AAAA,QAC9B;AAEA,cAAM,QAAQ,MAAM,KAAK,WAAW,QAAQ;AAG5C,YAAI,SAAS,WAAW,OAAO,SAAS,UAAU,KAAK;AACrD,sBAAY;AAEZ,cAAI,UAAU,KAAK,OAAO,YAAY;AACpC,kBAAM,aAAa,iBAAiB,kBAAkB,MAAM,aACxD,MAAM,aAAa,MACnB,KAAK,OAAO,aAAa,KAAK,IAAI,GAAG,OAAO;AAEhD,kBAAM,KAAK,MAAM,UAAU;AAC3B;AAAA,UACF;AAAA,QACF;AAEA,cAAM;AAAA,MACR,SAAS,KAAK;AACZ,YAAI,eAAe,eAAe;AAEhC,eAAK,IAAI,eAAe,OAAO,IAAI,cAAc,QAAQ,UAAU,KAAK,OAAO,YAAY;AACzF,wBAAY;AACZ,kBAAM,aAAa,eAAe,kBAAkB,IAAI,aACpD,IAAI,aAAa,MACjB,KAAK,OAAO,aAAa,KAAK,IAAI,GAAG,OAAO;AAChD,kBAAM,KAAK,MAAM,UAAU;AAC3B;AAAA,UACF;AACA,gBAAM;AAAA,QACR;AAEA,YAAI,eAAe,gBAAgB,IAAI,SAAS,cAAc;AAC5D,sBAAY,IAAI,aAAa,2BAA2B,KAAK,OAAO,OAAO,IAAI;AAC/E,cAAI,UAAU,KAAK,OAAO,YAAY;AACpC,kBAAM,KAAK,MAAM,KAAK,OAAO,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC;AAC9D;AAAA,UACF;AACA,gBAAM;AAAA,QACR;AAEA,oBAAY,IAAI,aAAc,IAAc,OAAO;AACnD,YAAI,UAAU,KAAK,OAAO,YAAY;AACpC,gBAAM,KAAK,MAAM,KAAK,OAAO,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC;AAC9D;AAAA,QACF;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAEA,UAAM,aAAa,IAAI,aAAa,8BAA8B;AAAA,EACpE;AAAA,EAEQ,SAAS,MAAc,QAA0C;AACvE,UAAM,OAAO,KAAK,OAAO,QAAQ,QAAQ,QAAQ,EAAE;AACnD,UAAM,MAAM,IAAI,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE;AAEpC,QAAI,QAAQ;AACV,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,YAAI,UAAU,UAAa,UAAU,MAAM;AACzC,cAAI,aAAa,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAEA,WAAO,IAAI,SAAS;AAAA,EACtB;AAAA,EAEA,MAAc,WAAW,UAA4C;AACnE,QAAI,OAAgE,CAAC;AACrE,UAAM,YAAY,SAAS,QAAQ,IAAI,cAAc,KAAK;AAE1D,QAAI;AACF,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B,QAAQ;AAAA,IAER;AAEA,UAAM,UAAU,KAAK,SAAS,KAAK,WAAW,QAAQ,SAAS,MAAM;AACrE,UAAM,UAAU,KAAK;AAErB,YAAQ,SAAS,QAAQ;AAAA,MACvB,KAAK;AACH,eAAO,IAAI,gBAAgB,SAAS,SAAS,SAAS;AAAA,MACxD,KAAK;AACH,eAAO,IAAI,oBAAoB,SAAS,SAAS,SAAS;AAAA,MAC5D,KAAK;AACH,eAAO,IAAI,eAAe,SAAS,SAAS,SAAS;AAAA,MACvD,KAAK;AACH,eAAO,IAAI,cAAc,SAAS,SAAS,SAAS;AAAA,MACtD,KAAK;AACH,eAAO,IAAI,cAAc,SAAS,SAAS,SAAS;AAAA,MACtD,KAAK,KAAK;AACR,cAAM,aAAa,SAAS,QAAQ,IAAI,aAAa;AACrD,eAAO,IAAI;AAAA,UACT;AAAA,UACA,aAAa,SAAS,YAAY,EAAE,IAAI;AAAA,UACxC;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,MACA;AACE,YAAI,SAAS,UAAU,KAAK;AAC1B,iBAAO,IAAI,YAAY,SAAS,SAAS,QAAQ,SAAS,SAAS;AAAA,QACrE;AACA,eAAO,IAAI,cAAc,SAAS,SAAS,QAAQ,SAAS,SAAS;AAAA,IACzE;AAAA,EACF;AAAA,EAEQ,MAAM,IAA2B;AACvC,WAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,EACzD;AACF;;;AC1KO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA,EAEvC,MAAM,KAAK,QAAyB,WAA0D;AAC5F,WAAO,KAAK,KAAK,KAAwB,kBAAkB,QAAQ,WAAW,MAAM;AAAA,EACtF;AAAA,EAkBA,MAAM,KAAK,QAAyB,WAA6E;AAC/G,WAAO,KAAK,KAAK,KAA2C,kBAAkB,QAAQ,WAAW,MAAM;AAAA,EACzG;AAAA,EAEA,MAAM,OAAO,OAAe,WAA0D;AACpF,WAAO,KAAK,KAAK,IAAuB,oBAAoB,mBAAmB,KAAK,CAAC,IAAI,QAAW,WAAW,MAAM;AAAA,EACvH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,iBAAiB,WAAmB,WAA8D;AACtG,WAAO,KAAK,KAAK,IAA2B,sBAAsB,mBAAmB,SAAS,CAAC,WAAW,QAAW,WAAW,MAAM;AAAA,EACxI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,kBAAkB,WAAmB,WAA+D;AACxG,WAAO,KAAK,KAAK,IAA4B,sBAAsB,mBAAmB,SAAS,CAAC,YAAY,QAAW,WAAW,MAAM;AAAA,EAC1I;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAAO,QAA2B,WAA4D;AAClG,QAAI,CAAC,OAAO,cAAc,CAAC,OAAO,OAAO;AACvC,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AACA,WAAO,KAAK,KAAK,KAA0B,oBAAoB,QAAQ,WAAW,MAAM;AAAA,EAC1F;AACF;;;AClEO,IAAM,oBAAN,MAAwB;AAAA,EAC7B,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA,EAEvC,MAAM,OAAO,QAA8B,WAAyD;AAClG,WAAO,KAAK,KAAK,KAAuB,uBAAuB,QAAQ,WAAW,MAAM;AAAA,EAC1F;AAAA,EAEA,MAAM,KAAK,QAA8B,WAA8D;AACrG,WAAO,KAAK,KAAK,IAA2B,uBAAuB,QAAmC,WAAW,MAAM;AAAA,EACzH;AAAA,EAEA,OAAO,QAAQ,QAA4C,WAAwD;AACjH,QAAI,OAAO;AACX,UAAM,QAAQ,QAAQ,SAAS;AAE/B,WAAO,MAAM;AACX,YAAM,SAAS,MAAM,KAAK,KAAK,EAAE,GAAG,QAAQ,MAAM,MAAM,GAAG,SAAS;AACpE,iBAAW,YAAY,OAAO,WAAW;AACvC,cAAM;AAAA,MACR;AACA,UAAI,OAAO,UAAU,SAAS,MAAO;AACrC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,IAAY,WAAyD;AAC7E,WAAO,KAAK,KAAK,IAAsB,uBAAuB,mBAAmB,EAAE,CAAC,IAAI,QAAW,WAAW,MAAM;AAAA,EACtH;AAAA,EAEA,MAAM,OAAO,IAAY,QAA8B,WAAyD;AAC9G,WAAO,KAAK,KAAK,MAAwB,uBAAuB,mBAAmB,EAAE,CAAC,IAAI,QAAQ,WAAW,MAAM;AAAA,EACrH;AAAA,EAEA,MAAM,OAAO,IAAY,WAAwE;AAC/F,WAAO,KAAK,KAAK,OAAwC,uBAAuB,mBAAmB,EAAE,CAAC,IAAI,WAAW,MAAM;AAAA,EAC7H;AAAA,EAEA,MAAM,UAAU,IAAY,QAA4B,WAAyD;AAC/G,WAAO,KAAK,KAAK,KAAuB,uBAAuB,mBAAmB,EAAE,CAAC,cAAc,QAAQ,WAAW,MAAM;AAAA,EAC9H;AAAA,EAEA,MAAM,QAAQ,IAAY,QAAgC,WAAgE;AACxH,WAAO,KAAK,KAAK,KAA8B,uBAAuB,mBAAmB,EAAE,CAAC,YAAY,QAAQ,WAAW,MAAM;AAAA,EACnI;AAAA,EAEA,MAAM,KAAK,QAA4B,WAA0D;AAC/F,WAAO,KAAK,KAAK,KAAwB,4BAA4B,QAAQ,WAAW,MAAM;AAAA,EAChG;AAAA,EAcA,MAAM,SAAS,QAAgC,WAAoF;AACjI,WAAO,KAAK,KAAK,KAAkD,4BAA4B,QAAQ,WAAW,MAAM;AAAA,EAC1H;AAAA,EAEA,MAAM,MAAM,WAA8D;AACxE,WAAO,KAAK,KAAK,IAA2B,6BAA6B,QAAW,WAAW,MAAM;AAAA,EACvG;AACF;;;AClEA,SAAS,YAAY,QAA2B;AAC9C,SAAO,MAAM,QAAQ,MAAM,IAAI,OAAO,KAAK,GAAG,IAAI;AACpD;AAEO,IAAM,uBAAN,MAA2B;AAAA,EAChC,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA,EAEvC,MAAM,KAAK,QAAiC,WAAiE;AAC3G,WAAO,KAAK,KAAK,IAA8B,4BAA4B,QAAmC,WAAW,MAAM;AAAA,EACjI;AAAA,EAEA,OAAO,QAAQ,QAA+C,WAA2D;AACvH,QAAI,OAAO;AACX,UAAM,QAAQ,QAAQ,SAAS;AAE/B,WAAO,MAAM;AACX,YAAM,SAAS,MAAM,KAAK,KAAK,EAAE,GAAG,QAAQ,MAAM,MAAM,GAAG,SAAS;AACpE,iBAAW,eAAe,OAAO,cAAc;AAC7C,cAAM;AAAA,MACR;AACA,UAAI,OAAO,aAAa,SAAS,MAAO;AACxC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,OAAO,QAAkC,WAAmE;AAChH,WAAO,KAAK,KAAK;AAAA,MACf;AAAA,MACA,EAAE,QAAQ,YAAY,OAAO,MAAM,EAAE;AAAA,MACrC,WAAW;AAAA,IACb;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,QAA8B,WAA4D;AAClG,WAAO,KAAK,KAAK,KAA0B,4BAA4B,QAAQ,WAAW,MAAM;AAAA,EAClG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,QAAQ,QAAmC,WAAoE;AACnH,WAAO,KAAK,KAAK;AAAA,MACf;AAAA,MACA,EAAE,QAAQ,YAAY,OAAO,MAAM,GAAG,QAAQ,OAAO,OAAO;AAAA,MAC5D,WAAW;AAAA,IACb;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,WAAW,QAAsC,WAAuE;AAC5H,WAAO,KAAK,KAAK;AAAA,MACf;AAAA,MACA,EAAE,QAAQ,YAAY,OAAO,MAAM,EAAE;AAAA,MACrC,WAAW;AAAA,IACb;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,OAAe,WAA4D;AACtF,WAAO,KAAK,KAAK,OAA4B,4BAA4B,mBAAmB,KAAK,CAAC,IAAI,WAAW,MAAM;AAAA,EACzH;AACF;;;ACvFO,IAAM,mBAAN,MAAuB;AAAA,EAC5B,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA,EAEvC,MAAM,OAAO,QAA6B,WAA8D;AACtG,WAAO,KAAK,KAAK,KAA4B,wBAAwB,QAAQ,WAAW,MAAM;AAAA,EAChG;AAAA,EAEA,MAAM,KAAK,WAA6D;AACtE,WAAO,KAAK,KAAK,IAA0B,wBAAwB,QAAW,WAAW,MAAM;AAAA,EACjG;AAAA,EAEA,MAAM,OAAO,IAAY,QAA6B,WAA8D;AAClH,WAAO,KAAK,KAAK,MAA6B,wBAAwB,mBAAmB,EAAE,CAAC,IAAI,QAAQ,WAAW,MAAM;AAAA,EAC3H;AAAA,EAEA,MAAM,OAAO,IAAY,WAAwE;AAC/F,WAAO,KAAK,KAAK,OAAwC,wBAAwB,mBAAmB,EAAE,CAAC,IAAI,WAAW,MAAM;AAAA,EAC9H;AACF;;;ACzBO,IAAM,oBAAN,MAAwB;AAAA,EAC7B,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA,EAEvC,MAAM,IAAI,WAA0D;AAClE,WAAO,KAAK,KAAK,IAAuB,yBAAyB,QAAW,WAAW,MAAM;AAAA,EAC/F;AAAA,EAEA,MAAM,MAAM,WAAsD;AAChE,WAAO,KAAK,KAAK,IAAmB,qBAAqB,QAAW,WAAW,MAAM;AAAA,EACvF;AACF;;;ACKO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA;AAAA,EAGvC,MAAM,OAAO,WAA4D;AACvE,WAAO,KAAK,KAAK,IAAyB,oBAAoB,QAAW,WAAW,MAAM;AAAA,EAC5F;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,MAAM,OAAe,WAA2D;AACpF,WAAO,KAAK,KAAK,KAAyB,mBAAmB,EAAE,MAAM,GAAG,WAAW,MAAM;AAAA,EAC3F;AACF;;;AC3BO,IAAM,oBAAN,MAAwB;AAAA,EAC7B,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA;AAAA,EAGvC,MAAM,KAAK,QAA8B,WAA8D;AACrG,WAAO,KAAK,KAAK;AAAA,MACf;AAAA,MACA;AAAA,MACA,WAAW;AAAA,IACb;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,UACJ,YACA,QACA,WAC4B;AAC5B,WAAO,KAAK,KAAK;AAAA,MACf,yBAAyB,mBAAmB,UAAU,CAAC;AAAA,MACvD;AAAA,MACA,WAAW;AAAA,IACb;AAAA,EACF;AACF;;;ACOO,IAAM,uBAAN,MAA2B;AAAA,EAChC,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA,EAEvC,MAAM,OAAO,QAAiC,WAA+E;AAC3H,WAAO,KAAK,KAAK,KAAK,qBAAqB,QAAQ,WAAW,MAAM;AAAA,EACtE;AAAA,EAEA,MAAM,KAAK,QAAiC,WAAiE;AAC3G,WAAO,KAAK,KAAK,IAA8B,qBAAqB,QAAmC,WAAW,MAAM;AAAA,EAC1H;AAAA;AAAA,EAGA,OAAO,QAAQ,QAA+C,WAA2D;AACvH,UAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAI,OAAO;AACX,eAAS;AACP,YAAM,SAAS,MAAM,KAAK,KAAK,EAAE,GAAG,QAAQ,MAAM,MAAM,GAAG,SAAS;AACpE,iBAAW,QAAQ,OAAO,MAAO,OAAM;AACvC,UAAI,OAAO,MAAM,SAAS,MAAO;AACjC,cAAQ;AAAA,IACV;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,IAAI,QAAgB,WAA0D;AAClF,WAAO,KAAK,KAAK,IAAuB,qBAAqB,mBAAmB,MAAM,CAAC,IAAI,QAAW,WAAW,MAAM;AAAA,EACzH;AAAA,EAEA,MAAM,OAAO,QAAgB,QAAiC,WAA+E;AAC3I,WAAO,KAAK,KAAK,MAAM,qBAAqB,mBAAmB,MAAM,CAAC,IAAI,QAAQ,WAAW,MAAM;AAAA,EACrG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAAO,QAAgB,WAAyD;AACpF,WAAO,KAAK,KAAK,OAAyB,qBAAqB,mBAAmB,MAAM,CAAC,IAAI,WAAW,MAAM;AAAA,EAChH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,eAAe,QAAgB,QAA8B,WAA+D;AAChI,WAAO,KAAK,KAAK;AAAA,MACf,qBAAqB,mBAAmB,MAAM,CAAC;AAAA,MAAoB;AAAA,MAAQ,WAAW;AAAA,IACxF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,SAAS,QAAgB,QAA6B,WAA6D;AACvH,WAAO,KAAK,KAAK;AAAA,MACf,qBAAqB,mBAAmB,MAAM,CAAC;AAAA,MAAa;AAAA,MAAmC,WAAW;AAAA,IAC5G;AAAA,EACF;AAAA;AAAA,EAGA,OAAO,YAAY,QAAgB,QAA6C,WAAuD;AACrI,QAAI;AACJ,eAAS;AACP,YAAM,SAAS,MAAM,KAAK,SAAS,QAAQ,EAAE,GAAG,QAAQ,OAAO,GAAG,SAAS;AAC3E,iBAAW,WAAW,OAAO,SAAU,OAAM;AAC7C,UAAI,CAAC,OAAO,WAAW,WAAW,CAAC,OAAO,WAAW,WAAY;AACjE,eAAS,OAAO,WAAW;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,QAAgB,QAA0B,WAA8E;AACvI,WAAO,KAAK,KAAK,KAAK,qBAAqB,mBAAmB,MAAM,CAAC,aAAa,QAAQ,WAAW,MAAM;AAAA,EAC7G;AAAA;AAAA,EAGA,MAAM,cAAc,QAAgB,WAAmB,QAA6B,WAA8E;AAChK,WAAO,KAAK,KAAK;AAAA,MACf,qBAAqB,mBAAmB,MAAM,CAAC,aAAa,mBAAmB,SAAS,CAAC;AAAA,MAAI;AAAA,MAAQ,WAAW;AAAA,IAClH;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,QAAgB,WAAmB,WAA6C;AAClG,UAAM,KAAK,KAAK;AAAA,MACd,qBAAqB,mBAAmB,MAAM,CAAC,aAAa,mBAAmB,SAAS,CAAC;AAAA,MAAI,WAAW;AAAA,IAC1G;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,mBAAmB,QAAgB,QAAkC,WAAmE;AAC5I,WAAO,KAAK,KAAK;AAAA,MACf,qBAAqB,mBAAmB,MAAM,CAAC;AAAA,MAAyB;AAAA,MAAQ,WAAW;AAAA,IAC7F;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,QAAgB,SAAiC,WAAkE;AAC9H,WAAO,KAAK,KAAK;AAAA,MACf,qBAAqB,mBAAmB,MAAM,CAAC;AAAA,MAC/C,SAAS,UAAU,EAAE,SAAS,OAAO,IAAI;AAAA,MACzC,WAAW;AAAA,IACb;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,QAAgB,WAAyD;AACxF,WAAO,KAAK,KAAK,KAAuB,qBAAqB,mBAAmB,MAAM,CAAC,eAAe,CAAC,GAAG,WAAW,MAAM;AAAA,EAC7H;AAAA;AAAA,EAGA,MAAM,QAAQ,QAAgB,WAAmE;AAC/F,WAAO,KAAK,KAAK,KAAiC,qBAAqB,mBAAmB,MAAM,CAAC,YAAY,CAAC,GAAG,WAAW,MAAM;AAAA,EACpI;AACF;;;ACjKA,IAAM,WAAW;AAEV,IAAM,WAAN,MAAe;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,QAAyB;AACnC,UAAM,WAA2B;AAAA,MAC/B,QAAQ,QAAQ;AAAA,MAChB,SAAS,QAAQ,WAAW;AAAA,MAC5B,SAAS,QAAQ,WAAW;AAAA,MAC5B,YAAY,QAAQ,cAAc;AAAA,MAClC,YAAY,QAAQ,cAAc;AAAA,IACpC;AAEA,UAAM,OAAO,IAAI,WAAW,QAAQ;AAEpC,SAAK,QAAQ,IAAI,cAAc,IAAI;AACnC,SAAK,YAAY,IAAI,kBAAkB,IAAI;AAC3C,SAAK,eAAe,IAAI,qBAAqB,IAAI;AACjD,SAAK,WAAW,IAAI,iBAAiB,IAAI;AACzC,SAAK,YAAY,IAAI,kBAAkB,IAAI;AAC3C,SAAK,QAAQ,IAAI,cAAc,IAAI;AACnC,SAAK,YAAY,IAAI,kBAAkB,IAAI;AAC3C,SAAK,eAAe,IAAI,qBAAqB,IAAI;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,uBACL,SACA,WACA,QACS;AAGT,UAAM,SAAS,UAAQ,QAAQ;AAC/B,UAAM,WAAW,OAAO,WAAW,UAAU,MAAM,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AACjF,QAAI;AACF,aAAO,OAAO,gBAAgB,OAAO,KAAK,SAAS,GAAG,OAAO,KAAK,QAAQ,CAAC;AAAA,IAC7E,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}
|