supersendtx 0.3.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +178 -9
- package/dist/index.js +201 -15
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
type ApiErrorCode = 'validation_error' | 'unauthorized' | 'forbidden' | 'not_found' | 'conflict' | 'plan_limit' | 'domain_limit' | 'idempotency_conflict' | 'rate_limited' | 'upstream_error' | 'not_configured' | 'internal_error';
|
|
1
2
|
type SendEmailParams = {
|
|
2
3
|
from: string | {
|
|
3
4
|
email: string;
|
|
@@ -7,23 +8,63 @@ type SendEmailParams = {
|
|
|
7
8
|
subject: string;
|
|
8
9
|
html?: string;
|
|
9
10
|
text?: string;
|
|
10
|
-
replyTo?: string;
|
|
11
|
-
reply_to?: string;
|
|
11
|
+
replyTo?: string | string[];
|
|
12
|
+
reply_to?: string | string[];
|
|
12
13
|
cc?: string | string[];
|
|
13
14
|
bcc?: string | string[];
|
|
15
|
+
tags?: Array<{
|
|
16
|
+
name: string;
|
|
17
|
+
value: string;
|
|
18
|
+
}> | Record<string, string>;
|
|
19
|
+
headers?: Record<string, string>;
|
|
20
|
+
tag?: string;
|
|
21
|
+
attachments?: Array<{
|
|
22
|
+
name: string;
|
|
23
|
+
content_type: string;
|
|
24
|
+
data: string;
|
|
25
|
+
content_id?: string;
|
|
26
|
+
}>;
|
|
27
|
+
scheduledAt?: string | Date;
|
|
28
|
+
scheduled_at?: string | Date;
|
|
29
|
+
/** Optional Idempotency-Key (24h TTL). */
|
|
30
|
+
idempotencyKey?: string;
|
|
14
31
|
};
|
|
15
32
|
type SendEmailResult = {
|
|
16
33
|
id: string;
|
|
17
34
|
status: string;
|
|
18
35
|
};
|
|
36
|
+
type BatchSendEmailResult = {
|
|
37
|
+
data: Array<{
|
|
38
|
+
index: number;
|
|
39
|
+
id?: string;
|
|
40
|
+
status?: string;
|
|
41
|
+
error?: {
|
|
42
|
+
message: string;
|
|
43
|
+
code?: string;
|
|
44
|
+
details?: unknown;
|
|
45
|
+
status_code?: number;
|
|
46
|
+
};
|
|
47
|
+
}>;
|
|
48
|
+
};
|
|
49
|
+
type UpdateEmailParams = {
|
|
50
|
+
scheduledAt?: string | Date;
|
|
51
|
+
scheduled_at?: string | Date;
|
|
52
|
+
cancel?: boolean;
|
|
53
|
+
};
|
|
19
54
|
type EmailListItem = {
|
|
20
55
|
id: string;
|
|
21
56
|
from: string;
|
|
22
57
|
to: string[];
|
|
58
|
+
cc: string[];
|
|
59
|
+
bcc: string[];
|
|
60
|
+
reply_to: string[];
|
|
23
61
|
subject: string;
|
|
24
62
|
status: string;
|
|
25
63
|
last_event: string | null;
|
|
26
64
|
bounce_reason: string | null;
|
|
65
|
+
tags: unknown;
|
|
66
|
+
scheduled_at: string | null;
|
|
67
|
+
cancelled_at: string | null;
|
|
27
68
|
created_at: string;
|
|
28
69
|
sent_at: string | null;
|
|
29
70
|
delivered_at: string | null;
|
|
@@ -31,8 +72,44 @@ type EmailListItem = {
|
|
|
31
72
|
};
|
|
32
73
|
type ListEmailsParams = {
|
|
33
74
|
limit?: number;
|
|
75
|
+
cursor?: string;
|
|
76
|
+
};
|
|
77
|
+
type ListEmailsResult = {
|
|
78
|
+
emails: EmailListItem[];
|
|
79
|
+
has_more: boolean;
|
|
80
|
+
next_cursor: string | null;
|
|
81
|
+
};
|
|
82
|
+
type ApiKeyScope = 'full' | 'sending';
|
|
83
|
+
type ApiKey = {
|
|
84
|
+
id: string;
|
|
85
|
+
name: string;
|
|
86
|
+
scope: ApiKeyScope;
|
|
87
|
+
prefix: string;
|
|
88
|
+
created_at: string;
|
|
89
|
+
last_used_at: string | null;
|
|
90
|
+
};
|
|
91
|
+
type ListApiKeysParams = {
|
|
92
|
+
limit?: number;
|
|
93
|
+
cursor?: string;
|
|
34
94
|
};
|
|
35
|
-
type
|
|
95
|
+
type ListApiKeysResult = {
|
|
96
|
+
data: ApiKey[];
|
|
97
|
+
has_more: boolean;
|
|
98
|
+
next_cursor: string | null;
|
|
99
|
+
};
|
|
100
|
+
type CreateApiKeyParams = {
|
|
101
|
+
name?: string;
|
|
102
|
+
scope?: ApiKeyScope;
|
|
103
|
+
};
|
|
104
|
+
type CreateApiKeyResult = {
|
|
105
|
+
id: string;
|
|
106
|
+
name: string;
|
|
107
|
+
scope: ApiKeyScope;
|
|
108
|
+
prefix: string;
|
|
109
|
+
token: string;
|
|
110
|
+
created_at: string;
|
|
111
|
+
};
|
|
112
|
+
type WebhookEventType = 'email.sent' | 'email.delivered' | 'email.delivery_delayed' | 'email.bounced' | 'email.complained' | 'email.opened' | 'email.clicked' | 'email.failed' | 'email.suppressed' | 'email.scheduled';
|
|
36
113
|
type WebhookEndpoint = {
|
|
37
114
|
id: string;
|
|
38
115
|
url: string;
|
|
@@ -45,10 +122,37 @@ type CreateWebhookParams = {
|
|
|
45
122
|
url: string;
|
|
46
123
|
events?: WebhookEventType[];
|
|
47
124
|
};
|
|
125
|
+
type UpdateWebhookParams = {
|
|
126
|
+
url?: string;
|
|
127
|
+
events?: WebhookEventType[];
|
|
128
|
+
enabled?: boolean;
|
|
129
|
+
};
|
|
48
130
|
type WebhookEndpointWithSecret = {
|
|
49
131
|
webhook: WebhookEndpoint;
|
|
50
132
|
secret: string;
|
|
51
133
|
};
|
|
134
|
+
type Suppression = {
|
|
135
|
+
id: string;
|
|
136
|
+
email: string;
|
|
137
|
+
reason: string | null;
|
|
138
|
+
source: string;
|
|
139
|
+
created_at: string;
|
|
140
|
+
updated_at: string;
|
|
141
|
+
};
|
|
142
|
+
type ListSuppressionsParams = {
|
|
143
|
+
limit?: number;
|
|
144
|
+
cursor?: string;
|
|
145
|
+
email?: string;
|
|
146
|
+
};
|
|
147
|
+
type ListSuppressionsResult = {
|
|
148
|
+
data: Suppression[];
|
|
149
|
+
has_more: boolean;
|
|
150
|
+
next_cursor: string | null;
|
|
151
|
+
};
|
|
152
|
+
type CreateSuppressionParams = {
|
|
153
|
+
email: string;
|
|
154
|
+
reason?: string;
|
|
155
|
+
};
|
|
52
156
|
type SuperSendTXOptions = {
|
|
53
157
|
baseUrl?: string;
|
|
54
158
|
fetch?: typeof fetch;
|
|
@@ -60,6 +164,8 @@ type Domain = {
|
|
|
60
164
|
status: DomainStatus | string;
|
|
61
165
|
created_at: string;
|
|
62
166
|
verified_at: string | null;
|
|
167
|
+
open_tracking?: boolean;
|
|
168
|
+
click_tracking?: boolean;
|
|
63
169
|
};
|
|
64
170
|
type DnsRecord = {
|
|
65
171
|
type: string;
|
|
@@ -111,14 +217,21 @@ type ApiErrorBody = {
|
|
|
111
217
|
error?: string | {
|
|
112
218
|
message?: string;
|
|
113
219
|
details?: unknown;
|
|
220
|
+
code?: string;
|
|
221
|
+
upgrade_url?: string;
|
|
114
222
|
};
|
|
115
223
|
};
|
|
116
224
|
|
|
117
225
|
declare class DomainsResource {
|
|
118
226
|
private readonly client;
|
|
119
227
|
constructor(client: SuperSendTX);
|
|
120
|
-
list(
|
|
228
|
+
list(params?: {
|
|
229
|
+
limit?: number;
|
|
230
|
+
cursor?: string;
|
|
231
|
+
}): Promise<{
|
|
121
232
|
domains: Domain[];
|
|
233
|
+
has_more: boolean;
|
|
234
|
+
next_cursor: string | null;
|
|
122
235
|
}>;
|
|
123
236
|
get(idOrName: string): Promise<{
|
|
124
237
|
domain: Domain;
|
|
@@ -146,22 +259,63 @@ declare class DomainsResource {
|
|
|
146
259
|
declare class EmailsResource {
|
|
147
260
|
private readonly client;
|
|
148
261
|
constructor(client: SuperSendTX);
|
|
149
|
-
list(params?: ListEmailsParams): Promise<
|
|
150
|
-
|
|
262
|
+
list(params?: ListEmailsParams): Promise<ListEmailsResult>;
|
|
263
|
+
get(id: string): Promise<{
|
|
264
|
+
email: EmailListItem;
|
|
151
265
|
}>;
|
|
152
266
|
send(params: SendEmailParams): Promise<SendEmailResult>;
|
|
267
|
+
batch(emails: SendEmailParams[]): Promise<BatchSendEmailResult>;
|
|
268
|
+
update(id: string, params: UpdateEmailParams): Promise<SendEmailResult>;
|
|
269
|
+
cancel(id: string): Promise<SendEmailResult>;
|
|
270
|
+
private serializeSendParams;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
declare class KeysResource {
|
|
274
|
+
private readonly client;
|
|
275
|
+
constructor(client: SuperSendTX);
|
|
276
|
+
list(params?: ListApiKeysParams): Promise<ListApiKeysResult>;
|
|
277
|
+
create(params?: CreateApiKeyParams): Promise<CreateApiKeyResult>;
|
|
278
|
+
remove(id: string): Promise<{
|
|
279
|
+
ok: boolean;
|
|
280
|
+
}>;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
declare class SuppressionsResource {
|
|
284
|
+
private readonly client;
|
|
285
|
+
constructor(client: SuperSendTX);
|
|
286
|
+
list(params?: ListSuppressionsParams): Promise<ListSuppressionsResult>;
|
|
287
|
+
create(params: CreateSuppressionParams): Promise<{
|
|
288
|
+
suppression: Suppression;
|
|
289
|
+
}>;
|
|
290
|
+
/** Remove by suppression id or email address. */
|
|
291
|
+
remove(idOrEmail: string): Promise<{
|
|
292
|
+
ok: boolean;
|
|
293
|
+
}>;
|
|
153
294
|
}
|
|
154
295
|
|
|
155
296
|
declare class WebhooksResource {
|
|
156
297
|
private readonly client;
|
|
157
298
|
constructor(client: SuperSendTX);
|
|
158
|
-
list(
|
|
299
|
+
list(params?: {
|
|
300
|
+
limit?: number;
|
|
301
|
+
cursor?: string;
|
|
302
|
+
}): Promise<{
|
|
159
303
|
webhooks: WebhookEndpoint[];
|
|
304
|
+
has_more: boolean;
|
|
305
|
+
next_cursor: string | null;
|
|
306
|
+
}>;
|
|
307
|
+
get(id: string): Promise<{
|
|
308
|
+
webhook: WebhookEndpoint;
|
|
160
309
|
}>;
|
|
161
310
|
create(params: CreateWebhookParams): Promise<WebhookEndpointWithSecret>;
|
|
311
|
+
update(id: string, params: UpdateWebhookParams): Promise<{
|
|
312
|
+
webhook: WebhookEndpoint;
|
|
313
|
+
}>;
|
|
162
314
|
delete(id: string): Promise<{
|
|
163
315
|
ok: boolean;
|
|
164
316
|
}>;
|
|
317
|
+
/** Verify an incoming webhook signature (same as `verifyWebhookSignature`). */
|
|
318
|
+
verify(secret: string, payload: string, header: string | null | undefined, toleranceSec?: number): boolean;
|
|
165
319
|
}
|
|
166
320
|
|
|
167
321
|
declare const DEFAULT_API_BASE_URL = "https://api.supersendtx.com";
|
|
@@ -171,6 +325,8 @@ declare class SuperSendTX {
|
|
|
171
325
|
readonly domains: DomainsResource;
|
|
172
326
|
readonly emails: EmailsResource;
|
|
173
327
|
readonly webhooks: WebhooksResource;
|
|
328
|
+
readonly apiKeys: KeysResource;
|
|
329
|
+
readonly suppressions: SuppressionsResource;
|
|
174
330
|
constructor(apiKey: string, options?: SuperSendTXOptions);
|
|
175
331
|
get baseUrl(): string;
|
|
176
332
|
get fetchImpl(): typeof fetch;
|
|
@@ -180,10 +336,23 @@ declare class SuperSendTX {
|
|
|
180
336
|
declare class SuperSendTXError extends Error {
|
|
181
337
|
readonly status: number;
|
|
182
338
|
readonly details?: unknown;
|
|
183
|
-
|
|
339
|
+
readonly code?: string;
|
|
340
|
+
readonly upgradeUrl?: string;
|
|
341
|
+
constructor(message: string, status: number, details?: unknown, options?: {
|
|
342
|
+
code?: string;
|
|
343
|
+
upgradeUrl?: string;
|
|
344
|
+
});
|
|
184
345
|
static fromResponse(status: number, body: ApiErrorBody): SuperSendTXError;
|
|
185
346
|
}
|
|
186
347
|
|
|
348
|
+
declare function signWebhookPayload(secret: string, payload: string, timestamp: number): string;
|
|
349
|
+
declare function buildSignatureHeader(secret: string, payload: string, timestamp?: number): string;
|
|
350
|
+
/**
|
|
351
|
+
* Verify a SuperSend TX webhook signature header (`SuperSendTX-Signature`).
|
|
352
|
+
* Expects HMAC-SHA256 over `${timestamp}.${rawBody}` with the endpoint secret.
|
|
353
|
+
*/
|
|
354
|
+
declare function verifyWebhookSignature(secret: string, payload: string, header: string | null | undefined, toleranceSec?: number): boolean;
|
|
355
|
+
|
|
187
356
|
/** Merge `include:host` into an existing SPF record (or create a minimal one). */
|
|
188
357
|
declare function mergeSpfInclude(existing: string | null | undefined, includeHost: string): string;
|
|
189
358
|
|
|
@@ -214,4 +383,4 @@ declare function applyDnsRecords(input: {
|
|
|
214
383
|
fetchImpl?: typeof fetch;
|
|
215
384
|
}): Promise<ApplyDnsResult>;
|
|
216
385
|
|
|
217
|
-
export { type ApplyDnsParams, type ApplyDnsRecordResult$1 as ApplyDnsRecordResult, type ApplyDnsResult$1 as ApplyDnsResult, type CreateDomainParams, type CreateDomainResult, type CreateWebhookParams, DEFAULT_API_BASE_URL, type DnsProviderName$1 as DnsProviderName, type DnsRecord, type Domain, type DomainStatus, type EmailListItem, type ListEmailsParams, type SendEmailParams, type SendEmailResult, SuperSendTX, SuperSendTXError, type SuperSendTXOptions, type VerifyDomainResult, type WebhookEndpoint, type WebhookEndpointWithSecret, type WebhookEventType, applyDnsRecords, mergeSpfInclude };
|
|
386
|
+
export { type ApiErrorCode, type ApiKey, type ApiKeyScope, type ApplyDnsParams, type ApplyDnsRecordResult$1 as ApplyDnsRecordResult, type ApplyDnsResult$1 as ApplyDnsResult, type BatchSendEmailResult, type CreateApiKeyParams, type CreateApiKeyResult, type CreateDomainParams, type CreateDomainResult, type CreateSuppressionParams, type CreateWebhookParams, DEFAULT_API_BASE_URL, type DnsProviderName$1 as DnsProviderName, type DnsRecord, type Domain, type DomainStatus, type EmailListItem, type ListApiKeysParams, type ListApiKeysResult, type ListEmailsParams, type ListEmailsResult, type ListSuppressionsParams, type ListSuppressionsResult, type SendEmailParams, type SendEmailResult, SuperSendTX, SuperSendTXError, type SuperSendTXOptions, type Suppression, type UpdateEmailParams, type UpdateWebhookParams, type VerifyDomainResult, type WebhookEndpoint, type WebhookEndpointWithSecret, type WebhookEventType, applyDnsRecords, buildSignatureHeader, mergeSpfInclude, signWebhookPayload, verifyWebhookSignature };
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
// src/errors.ts
|
|
2
2
|
var SuperSendTXError = class _SuperSendTXError extends Error {
|
|
3
|
-
constructor(message, status, details) {
|
|
3
|
+
constructor(message, status, details, options) {
|
|
4
4
|
super(message);
|
|
5
5
|
this.name = "SuperSendTXError";
|
|
6
6
|
this.status = status;
|
|
7
7
|
this.details = details;
|
|
8
|
+
this.code = options?.code;
|
|
9
|
+
this.upgradeUrl = options?.upgradeUrl;
|
|
8
10
|
}
|
|
9
11
|
static fromResponse(status, body) {
|
|
10
12
|
const err = body.error;
|
|
11
13
|
const message = typeof err === "string" ? err : err?.message || `Request failed with status ${status}`;
|
|
12
14
|
const details = typeof err === "object" && err ? err.details : void 0;
|
|
13
|
-
|
|
15
|
+
const code = typeof err === "object" && err && "code" in err ? String(err.code) : void 0;
|
|
16
|
+
const upgradeUrl = typeof err === "object" && err && "upgrade_url" in err ? String(err.upgrade_url) : void 0;
|
|
17
|
+
return new _SuperSendTXError(message, status, details, { code, upgradeUrl });
|
|
14
18
|
}
|
|
15
19
|
};
|
|
16
20
|
|
|
@@ -337,8 +341,12 @@ var DomainsResource = class {
|
|
|
337
341
|
constructor(client) {
|
|
338
342
|
this.client = client;
|
|
339
343
|
}
|
|
340
|
-
async list() {
|
|
341
|
-
|
|
344
|
+
async list(params = {}) {
|
|
345
|
+
const search = new URLSearchParams();
|
|
346
|
+
if (params.limit != null) search.set("limit", String(params.limit));
|
|
347
|
+
if (params.cursor) search.set("cursor", params.cursor);
|
|
348
|
+
const query = search.toString();
|
|
349
|
+
return this.client.request(`/domains${query ? `?${query}` : ""}`, { method: "GET" });
|
|
342
350
|
}
|
|
343
351
|
async get(idOrName) {
|
|
344
352
|
return this.client.request(`/domains/${encodeURIComponent(idOrName)}`, { method: "GET" });
|
|
@@ -400,8 +408,16 @@ var EmailsResource = class {
|
|
|
400
408
|
this.client = client;
|
|
401
409
|
}
|
|
402
410
|
async list(params = {}) {
|
|
403
|
-
const
|
|
404
|
-
|
|
411
|
+
const search = new URLSearchParams();
|
|
412
|
+
if (params.limit != null) search.set("limit", String(params.limit));
|
|
413
|
+
if (params.cursor) search.set("cursor", params.cursor);
|
|
414
|
+
const query = search.toString();
|
|
415
|
+
return this.client.request(`/emails${query ? `?${query}` : ""}`, {
|
|
416
|
+
method: "GET"
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
async get(id) {
|
|
420
|
+
return this.client.request(`/emails/${encodeURIComponent(id)}`, {
|
|
405
421
|
method: "GET"
|
|
406
422
|
});
|
|
407
423
|
}
|
|
@@ -411,26 +427,181 @@ var EmailsResource = class {
|
|
|
411
427
|
to: params.to,
|
|
412
428
|
subject: params.subject
|
|
413
429
|
};
|
|
414
|
-
if (params.html) payload.html = params.html;
|
|
415
|
-
if (params.text) payload.text = params.text;
|
|
430
|
+
if (params.html !== void 0) payload.html = params.html;
|
|
431
|
+
if (params.text !== void 0) payload.text = params.text;
|
|
416
432
|
const replyTo = params.replyTo ?? params.reply_to;
|
|
417
|
-
if (replyTo) payload.reply_to = replyTo;
|
|
418
|
-
if (params.cc) payload.cc = params.cc;
|
|
419
|
-
if (params.bcc) payload.bcc = params.bcc;
|
|
433
|
+
if (replyTo !== void 0) payload.reply_to = replyTo;
|
|
434
|
+
if (params.cc !== void 0) payload.cc = params.cc;
|
|
435
|
+
if (params.bcc !== void 0) payload.bcc = params.bcc;
|
|
436
|
+
if (params.tags !== void 0) payload.tags = params.tags;
|
|
437
|
+
if (params.headers !== void 0) payload.headers = params.headers;
|
|
438
|
+
if (params.tag !== void 0) payload.tag = params.tag;
|
|
439
|
+
if (params.attachments !== void 0) payload.attachments = params.attachments;
|
|
440
|
+
const scheduledAt = params.scheduledAt ?? params.scheduled_at;
|
|
441
|
+
if (scheduledAt !== void 0) {
|
|
442
|
+
payload.scheduled_at = scheduledAt instanceof Date ? scheduledAt.toISOString() : scheduledAt;
|
|
443
|
+
}
|
|
444
|
+
const headers = {};
|
|
445
|
+
if (params.idempotencyKey) {
|
|
446
|
+
headers["Idempotency-Key"] = params.idempotencyKey;
|
|
447
|
+
}
|
|
420
448
|
return this.client.request("/emails", {
|
|
421
449
|
method: "POST",
|
|
450
|
+
headers,
|
|
422
451
|
body: JSON.stringify(payload)
|
|
423
452
|
});
|
|
424
453
|
}
|
|
454
|
+
async batch(emails) {
|
|
455
|
+
return this.client.request("/emails/batch", {
|
|
456
|
+
method: "POST",
|
|
457
|
+
body: JSON.stringify({ emails: emails.map((email) => this.serializeSendParams(email)) })
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
async update(id, params) {
|
|
461
|
+
const payload = {};
|
|
462
|
+
if (params.cancel !== void 0) payload.cancel = params.cancel;
|
|
463
|
+
const scheduledAt = params.scheduledAt ?? params.scheduled_at;
|
|
464
|
+
if (scheduledAt !== void 0) {
|
|
465
|
+
payload.scheduled_at = scheduledAt instanceof Date ? scheduledAt.toISOString() : scheduledAt;
|
|
466
|
+
}
|
|
467
|
+
return this.client.request(`/emails/${encodeURIComponent(id)}`, {
|
|
468
|
+
method: "PATCH",
|
|
469
|
+
body: JSON.stringify(payload)
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
async cancel(id) {
|
|
473
|
+
return this.update(id, { cancel: true });
|
|
474
|
+
}
|
|
475
|
+
serializeSendParams(params) {
|
|
476
|
+
const payload = {
|
|
477
|
+
from: params.from,
|
|
478
|
+
to: params.to,
|
|
479
|
+
subject: params.subject
|
|
480
|
+
};
|
|
481
|
+
if (params.html !== void 0) payload.html = params.html;
|
|
482
|
+
if (params.text !== void 0) payload.text = params.text;
|
|
483
|
+
const replyTo = params.replyTo ?? params.reply_to;
|
|
484
|
+
if (replyTo !== void 0) payload.reply_to = replyTo;
|
|
485
|
+
if (params.cc !== void 0) payload.cc = params.cc;
|
|
486
|
+
if (params.bcc !== void 0) payload.bcc = params.bcc;
|
|
487
|
+
if (params.tags !== void 0) payload.tags = params.tags;
|
|
488
|
+
if (params.headers !== void 0) payload.headers = params.headers;
|
|
489
|
+
if (params.tag !== void 0) payload.tag = params.tag;
|
|
490
|
+
if (params.attachments !== void 0) payload.attachments = params.attachments;
|
|
491
|
+
const scheduledAt = params.scheduledAt ?? params.scheduled_at;
|
|
492
|
+
if (scheduledAt !== void 0) {
|
|
493
|
+
payload.scheduled_at = scheduledAt instanceof Date ? scheduledAt.toISOString() : scheduledAt;
|
|
494
|
+
}
|
|
495
|
+
return payload;
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
// src/keys.ts
|
|
500
|
+
var KeysResource = class {
|
|
501
|
+
constructor(client) {
|
|
502
|
+
this.client = client;
|
|
503
|
+
}
|
|
504
|
+
async list(params = {}) {
|
|
505
|
+
const search = new URLSearchParams();
|
|
506
|
+
if (params.limit != null) search.set("limit", String(params.limit));
|
|
507
|
+
if (params.cursor) search.set("cursor", params.cursor);
|
|
508
|
+
const query = search.toString();
|
|
509
|
+
return this.client.request(`/api-keys${query ? `?${query}` : ""}`, {
|
|
510
|
+
method: "GET"
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
async create(params = {}) {
|
|
514
|
+
return this.client.request("/api-keys", {
|
|
515
|
+
method: "POST",
|
|
516
|
+
body: JSON.stringify({
|
|
517
|
+
...params.name ? { name: params.name } : {},
|
|
518
|
+
...params.scope ? { scope: params.scope } : {}
|
|
519
|
+
})
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
async remove(id) {
|
|
523
|
+
return this.client.request(`/api-keys/${encodeURIComponent(id)}`, {
|
|
524
|
+
method: "DELETE"
|
|
525
|
+
});
|
|
526
|
+
}
|
|
425
527
|
};
|
|
426
528
|
|
|
427
|
-
// src/
|
|
529
|
+
// src/suppressions.ts
|
|
530
|
+
var SuppressionsResource = class {
|
|
531
|
+
constructor(client) {
|
|
532
|
+
this.client = client;
|
|
533
|
+
}
|
|
534
|
+
async list(params = {}) {
|
|
535
|
+
const search = new URLSearchParams();
|
|
536
|
+
if (params.limit != null) search.set("limit", String(params.limit));
|
|
537
|
+
if (params.cursor) search.set("cursor", params.cursor);
|
|
538
|
+
if (params.email) search.set("email", params.email);
|
|
539
|
+
const query = search.toString();
|
|
540
|
+
return this.client.request(`/suppressions${query ? `?${query}` : ""}`, { method: "GET" });
|
|
541
|
+
}
|
|
542
|
+
async create(params) {
|
|
543
|
+
return this.client.request("/suppressions", {
|
|
544
|
+
method: "POST",
|
|
545
|
+
body: JSON.stringify(params)
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
/** Remove by suppression id or email address. */
|
|
549
|
+
async remove(idOrEmail) {
|
|
550
|
+
if (idOrEmail.includes("@")) {
|
|
551
|
+
return this.client.request(`/suppressions?email=${encodeURIComponent(idOrEmail)}`, {
|
|
552
|
+
method: "DELETE"
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
return this.client.request(`/suppressions/${encodeURIComponent(idOrEmail)}`, {
|
|
556
|
+
method: "DELETE"
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
// src/webhooks/verify.ts
|
|
562
|
+
import { createHmac, timingSafeEqual } from "crypto";
|
|
563
|
+
function signWebhookPayload(secret, payload, timestamp) {
|
|
564
|
+
const signed = `${timestamp}.${payload}`;
|
|
565
|
+
return createHmac("sha256", secret).update(signed).digest("hex");
|
|
566
|
+
}
|
|
567
|
+
function buildSignatureHeader(secret, payload, timestamp = Math.floor(Date.now() / 1e3)) {
|
|
568
|
+
const signature = signWebhookPayload(secret, payload, timestamp);
|
|
569
|
+
return `t=${timestamp},v1=${signature}`;
|
|
570
|
+
}
|
|
571
|
+
function verifyWebhookSignature(secret, payload, header, toleranceSec = 300) {
|
|
572
|
+
if (!header) return false;
|
|
573
|
+
const parts = Object.fromEntries(
|
|
574
|
+
header.split(",").map((part) => {
|
|
575
|
+
const [key, value] = part.trim().split("=");
|
|
576
|
+
return [key, value];
|
|
577
|
+
})
|
|
578
|
+
);
|
|
579
|
+
const timestamp = Number(parts.t);
|
|
580
|
+
const signature = parts.v1;
|
|
581
|
+
if (!timestamp || !signature) return false;
|
|
582
|
+
if (Math.abs(Math.floor(Date.now() / 1e3) - timestamp) > toleranceSec) return false;
|
|
583
|
+
const expected = signWebhookPayload(secret, payload, timestamp);
|
|
584
|
+
try {
|
|
585
|
+
return timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
|
|
586
|
+
} catch {
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// src/webhooks/index.ts
|
|
428
592
|
var WebhooksResource = class {
|
|
429
593
|
constructor(client) {
|
|
430
594
|
this.client = client;
|
|
431
595
|
}
|
|
432
|
-
async list() {
|
|
433
|
-
|
|
596
|
+
async list(params = {}) {
|
|
597
|
+
const search = new URLSearchParams();
|
|
598
|
+
if (params.limit != null) search.set("limit", String(params.limit));
|
|
599
|
+
if (params.cursor) search.set("cursor", params.cursor);
|
|
600
|
+
const query = search.toString();
|
|
601
|
+
return this.client.request(`/webhooks${query ? `?${query}` : ""}`, { method: "GET" });
|
|
602
|
+
}
|
|
603
|
+
async get(id) {
|
|
604
|
+
return this.client.request(`/webhooks/${encodeURIComponent(id)}`, { method: "GET" });
|
|
434
605
|
}
|
|
435
606
|
async create(params) {
|
|
436
607
|
return this.client.request("/webhooks", {
|
|
@@ -438,9 +609,19 @@ var WebhooksResource = class {
|
|
|
438
609
|
body: JSON.stringify(params)
|
|
439
610
|
});
|
|
440
611
|
}
|
|
612
|
+
async update(id, params) {
|
|
613
|
+
return this.client.request(`/webhooks/${encodeURIComponent(id)}`, {
|
|
614
|
+
method: "PATCH",
|
|
615
|
+
body: JSON.stringify(params)
|
|
616
|
+
});
|
|
617
|
+
}
|
|
441
618
|
async delete(id) {
|
|
442
619
|
return this.client.request(`/webhooks/${id}`, { method: "DELETE" });
|
|
443
620
|
}
|
|
621
|
+
/** Verify an incoming webhook signature (same as `verifyWebhookSignature`). */
|
|
622
|
+
verify(secret, payload, header, toleranceSec = 300) {
|
|
623
|
+
return verifyWebhookSignature(secret, payload, header, toleranceSec);
|
|
624
|
+
}
|
|
444
625
|
};
|
|
445
626
|
|
|
446
627
|
// src/client.ts
|
|
@@ -455,6 +636,8 @@ var SuperSendTX = class {
|
|
|
455
636
|
this.domains = new DomainsResource(this);
|
|
456
637
|
this.emails = new EmailsResource(this);
|
|
457
638
|
this.webhooks = new WebhooksResource(this);
|
|
639
|
+
this.apiKeys = new KeysResource(this);
|
|
640
|
+
this.suppressions = new SuppressionsResource(this);
|
|
458
641
|
}
|
|
459
642
|
get baseUrl() {
|
|
460
643
|
return (this.options.baseUrl || DEFAULT_API_BASE_URL).replace(/\/$/, "");
|
|
@@ -483,5 +666,8 @@ export {
|
|
|
483
666
|
SuperSendTX,
|
|
484
667
|
SuperSendTXError,
|
|
485
668
|
applyDnsRecords,
|
|
486
|
-
|
|
669
|
+
buildSignatureHeader,
|
|
670
|
+
mergeSpfInclude,
|
|
671
|
+
signWebhookPayload,
|
|
672
|
+
verifyWebhookSignature
|
|
487
673
|
};
|