@develemail/sdk 0.1.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -0
- package/dist/index.cjs +576 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +533 -10
- package/dist/index.d.ts +533 -10
- package/dist/index.js +570 -22
- package/dist/index.js.map +1 -1
- package/package.json +17 -3
package/dist/index.cjs
CHANGED
|
@@ -21,56 +21,610 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
DevelEmail: () => DevelEmail,
|
|
24
|
-
DevelEmailError: () => DevelEmailError
|
|
24
|
+
DevelEmailError: () => DevelEmailError,
|
|
25
|
+
EMAIL_EVENT_TYPES: () => EMAIL_EVENT_TYPES,
|
|
26
|
+
EMAIL_STATUSES: () => EMAIL_STATUSES,
|
|
27
|
+
SMS_STATUSES: () => SMS_STATUSES,
|
|
28
|
+
verifyWebhookSignature: () => verifyWebhookSignature
|
|
25
29
|
});
|
|
26
30
|
module.exports = __toCommonJS(index_exports);
|
|
31
|
+
|
|
32
|
+
// src/errors.ts
|
|
27
33
|
var DevelEmailError = class extends Error {
|
|
28
|
-
constructor(status, message) {
|
|
34
|
+
constructor(status, message, code, details) {
|
|
29
35
|
super(message);
|
|
30
36
|
this.status = status;
|
|
37
|
+
this.code = code;
|
|
38
|
+
this.details = details;
|
|
31
39
|
this.name = "DevelEmailError";
|
|
32
40
|
}
|
|
33
41
|
status;
|
|
42
|
+
code;
|
|
43
|
+
details;
|
|
34
44
|
};
|
|
35
|
-
|
|
45
|
+
|
|
46
|
+
// src/client.ts
|
|
47
|
+
var DEFAULT_MAX_RETRIES = 3;
|
|
48
|
+
var BASE_DELAY_MS = 500;
|
|
49
|
+
var MAX_DELAY_MS = 3e4;
|
|
50
|
+
function sleep(ms) {
|
|
51
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
52
|
+
}
|
|
53
|
+
function isRetryable(status) {
|
|
54
|
+
return status >= 500 || status === 429;
|
|
55
|
+
}
|
|
56
|
+
function parseErrorBody(body) {
|
|
57
|
+
if (typeof body === "object" && body !== null) {
|
|
58
|
+
const b = body;
|
|
59
|
+
const { message, error, statusCode, ...rest } = b;
|
|
60
|
+
return {
|
|
61
|
+
message: typeof message === "string" ? message : "Unknown error",
|
|
62
|
+
code: typeof error === "string" ? error : void 0,
|
|
63
|
+
details: Object.keys(rest).length > 0 ? rest : void 0
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return { message: "Unknown error" };
|
|
67
|
+
}
|
|
68
|
+
var HttpClient = class {
|
|
69
|
+
baseUrl;
|
|
70
|
+
apiKey;
|
|
71
|
+
maxRetries;
|
|
36
72
|
constructor(config) {
|
|
37
|
-
this.
|
|
73
|
+
this.baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
74
|
+
this.apiKey = config.apiKey;
|
|
75
|
+
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
38
76
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return this.request("POST", "/v1/emails", input);
|
|
77
|
+
async get(path) {
|
|
78
|
+
return this.request("GET", path);
|
|
42
79
|
}
|
|
43
|
-
async
|
|
44
|
-
return this.request("
|
|
80
|
+
async post(path, body, extraHeaders) {
|
|
81
|
+
return this.request("POST", path, body, extraHeaders);
|
|
82
|
+
}
|
|
83
|
+
async put(path, body, extraHeaders) {
|
|
84
|
+
return this.request("PUT", path, body, extraHeaders);
|
|
85
|
+
}
|
|
86
|
+
async patch(path, body, extraHeaders) {
|
|
87
|
+
return this.request("PATCH", path, body, extraHeaders);
|
|
45
88
|
}
|
|
46
|
-
async
|
|
47
|
-
|
|
89
|
+
async delete(path, extraHeaders) {
|
|
90
|
+
return this.request("DELETE", path, void 0, extraHeaders);
|
|
91
|
+
}
|
|
92
|
+
async request(method, path, body, extraHeaders) {
|
|
93
|
+
const url = `${this.baseUrl}${path}`;
|
|
94
|
+
const headers = {
|
|
95
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
96
|
+
"Content-Type": "application/json",
|
|
97
|
+
...extraHeaders
|
|
98
|
+
};
|
|
99
|
+
const init = {
|
|
48
100
|
method,
|
|
49
|
-
headers
|
|
50
|
-
Authorization: `Bearer ${this.config.apiKey}`,
|
|
51
|
-
"Content-Type": "application/json"
|
|
52
|
-
},
|
|
101
|
+
headers,
|
|
53
102
|
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
103
|
+
};
|
|
104
|
+
let lastError;
|
|
105
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
106
|
+
let res;
|
|
107
|
+
try {
|
|
108
|
+
res = await fetch(url, init);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
lastError = err;
|
|
111
|
+
if (attempt < this.maxRetries) {
|
|
112
|
+
await sleep(this.backoff(attempt));
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
throw new DevelEmailError(
|
|
116
|
+
0,
|
|
117
|
+
err instanceof Error ? err.message : "Network error",
|
|
118
|
+
"network_error"
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
if (res.ok) {
|
|
122
|
+
if (res.status === 204) return void 0;
|
|
123
|
+
return res.json();
|
|
124
|
+
}
|
|
125
|
+
const errorBody = await res.json().catch(() => ({}));
|
|
126
|
+
const parsed = parseErrorBody(errorBody);
|
|
127
|
+
if (isRetryable(res.status) && attempt < this.maxRetries) {
|
|
128
|
+
const retryAfter = res.headers.get("Retry-After");
|
|
129
|
+
const delay = retryAfter ? parseInt(retryAfter, 10) * 1e3 : this.backoff(attempt);
|
|
130
|
+
await sleep(delay);
|
|
131
|
+
lastError = new DevelEmailError(
|
|
132
|
+
res.status,
|
|
133
|
+
parsed.message,
|
|
134
|
+
parsed.code,
|
|
135
|
+
parsed.details
|
|
136
|
+
);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
57
139
|
throw new DevelEmailError(
|
|
58
140
|
res.status,
|
|
59
|
-
|
|
141
|
+
parsed.message,
|
|
142
|
+
parsed.code,
|
|
143
|
+
parsed.details
|
|
60
144
|
);
|
|
61
145
|
}
|
|
62
|
-
|
|
146
|
+
if (lastError instanceof DevelEmailError) throw lastError;
|
|
147
|
+
throw new DevelEmailError(
|
|
148
|
+
0,
|
|
149
|
+
lastError instanceof Error ? lastError.message : "Request failed",
|
|
150
|
+
"network_error"
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
backoff(attempt) {
|
|
154
|
+
const delay = BASE_DELAY_MS * 2 ** attempt;
|
|
155
|
+
const jitter = delay * 0.2 * Math.random();
|
|
156
|
+
return Math.min(delay + jitter, MAX_DELAY_MS);
|
|
63
157
|
}
|
|
64
158
|
};
|
|
159
|
+
|
|
160
|
+
// ../core/src/reserved-domains.ts
|
|
161
|
+
var RESERVED_DOMAINS = ["example.com", "example.net", "example.org"];
|
|
162
|
+
var RESERVED_TLDS = ["test", "example", "invalid", "localhost"];
|
|
163
|
+
function isReservedDomain(domain) {
|
|
164
|
+
const normalized = domain.trim().toLowerCase().replace(/\.$/, "");
|
|
165
|
+
if (!normalized) return false;
|
|
166
|
+
if (RESERVED_DOMAINS.includes(normalized)) return true;
|
|
167
|
+
const tld = normalized.split(".").pop() ?? "";
|
|
168
|
+
return RESERVED_TLDS.includes(tld);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/attachment-encoding.ts
|
|
172
|
+
function encodeAttachmentContent(content) {
|
|
173
|
+
return typeof content === "string" ? content : Buffer.from(content).toString("base64");
|
|
174
|
+
}
|
|
175
|
+
function encodeAttachments(attachments) {
|
|
176
|
+
if (!attachments) return void 0;
|
|
177
|
+
return attachments.map((attachment) => ({
|
|
178
|
+
filename: attachment.filename,
|
|
179
|
+
contentType: attachment.contentType,
|
|
180
|
+
content: encodeAttachmentContent(attachment.content)
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/emails.ts
|
|
185
|
+
function toWirePayload(input) {
|
|
186
|
+
return { ...input, attachments: encodeAttachments(input.attachments) };
|
|
187
|
+
}
|
|
188
|
+
function extractDomain(email) {
|
|
189
|
+
return email.split("@")[1] ?? "";
|
|
190
|
+
}
|
|
191
|
+
function reservedRecipientError(recipient) {
|
|
192
|
+
const domain = extractDomain(recipient);
|
|
193
|
+
return new DevelEmailError(
|
|
194
|
+
400,
|
|
195
|
+
`Recipient '${recipient}' uses reserved domain '${domain}', which cannot receive mail`,
|
|
196
|
+
"reserved_recipient_domain",
|
|
197
|
+
{ recipient, domain }
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
function findReservedRecipient(input) {
|
|
201
|
+
const toAddresses = Array.isArray(input.to) ? input.to : [input.to];
|
|
202
|
+
return toAddresses.find((addr) => isReservedDomain(extractDomain(addr))) ?? null;
|
|
203
|
+
}
|
|
204
|
+
var Emails = class {
|
|
205
|
+
constructor(http) {
|
|
206
|
+
this.http = http;
|
|
207
|
+
}
|
|
208
|
+
http;
|
|
209
|
+
async send(input, options) {
|
|
210
|
+
const reserved = findReservedRecipient(input);
|
|
211
|
+
if (reserved) throw reservedRecipientError(reserved);
|
|
212
|
+
const key = options?.idempotencyKey ?? crypto.randomUUID();
|
|
213
|
+
return this.http.post("/v1/emails", toWirePayload(input), {
|
|
214
|
+
"Idempotency-Key": key
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
// Rejects reserved recipients client-side but, matching the server's
|
|
218
|
+
// per-item batch semantics, does not fail the whole batch: deliverable
|
|
219
|
+
// items still go out, and each reserved item is named in `results` with
|
|
220
|
+
// an `error` instead of being silently dropped.
|
|
221
|
+
async batch(emails, options) {
|
|
222
|
+
const rejections = /* @__PURE__ */ new Map();
|
|
223
|
+
emails.forEach((email, index) => {
|
|
224
|
+
const reserved = findReservedRecipient(email);
|
|
225
|
+
if (reserved) {
|
|
226
|
+
rejections.set(index, {
|
|
227
|
+
index,
|
|
228
|
+
error: reservedRecipientError(reserved).message
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
const deliverable = emails.filter((_, index) => !rejections.has(index));
|
|
233
|
+
if (deliverable.length === 0) {
|
|
234
|
+
return {
|
|
235
|
+
results: emails.map((_, index) => rejections.get(index)),
|
|
236
|
+
created: 0,
|
|
237
|
+
errors: rejections.size
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
const key = options?.idempotencyKey ?? crypto.randomUUID();
|
|
241
|
+
const response = await this.http.post(
|
|
242
|
+
"/v1/emails/batch",
|
|
243
|
+
{ emails: deliverable.map(toWirePayload) },
|
|
244
|
+
{ "Idempotency-Key": key }
|
|
245
|
+
);
|
|
246
|
+
const results = [];
|
|
247
|
+
let sent = 0;
|
|
248
|
+
for (let index = 0; index < emails.length; index++) {
|
|
249
|
+
const rejection = rejections.get(index);
|
|
250
|
+
results.push(rejection ?? { ...response.results[sent++], index });
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
results,
|
|
254
|
+
created: response.created,
|
|
255
|
+
errors: response.errors + rejections.size,
|
|
256
|
+
limitReached: response.limitReached
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
async get(id) {
|
|
260
|
+
return this.http.get(`/v1/emails/${encodeURIComponent(id)}`);
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
// src/domains.ts
|
|
265
|
+
var Domains = class {
|
|
266
|
+
constructor(http) {
|
|
267
|
+
this.http = http;
|
|
268
|
+
}
|
|
269
|
+
http;
|
|
270
|
+
async list() {
|
|
271
|
+
return this.http.get("/domains");
|
|
272
|
+
}
|
|
273
|
+
async get(id) {
|
|
274
|
+
return this.http.get(`/domains/${encodeURIComponent(id)}`);
|
|
275
|
+
}
|
|
276
|
+
async create(input) {
|
|
277
|
+
return this.http.post("/domains", input);
|
|
278
|
+
}
|
|
279
|
+
async delete(id) {
|
|
280
|
+
await this.http.delete(`/domains/${encodeURIComponent(id)}`);
|
|
281
|
+
}
|
|
282
|
+
async verify(id) {
|
|
283
|
+
return this.http.post(
|
|
284
|
+
`/domains/${encodeURIComponent(id)}/verify`,
|
|
285
|
+
void 0
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// src/templates.ts
|
|
291
|
+
var Templates = class {
|
|
292
|
+
constructor(http) {
|
|
293
|
+
this.http = http;
|
|
294
|
+
}
|
|
295
|
+
http;
|
|
296
|
+
async list() {
|
|
297
|
+
return this.http.get("/templates");
|
|
298
|
+
}
|
|
299
|
+
async get(id) {
|
|
300
|
+
return this.http.get(`/templates/${encodeURIComponent(id)}`);
|
|
301
|
+
}
|
|
302
|
+
async create(input) {
|
|
303
|
+
return this.http.post("/templates", input);
|
|
304
|
+
}
|
|
305
|
+
async update(id, input) {
|
|
306
|
+
return this.http.put(
|
|
307
|
+
`/templates/${encodeURIComponent(id)}`,
|
|
308
|
+
input
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
async delete(id) {
|
|
312
|
+
await this.http.delete(`/templates/${encodeURIComponent(id)}`);
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
// src/campaigns.ts
|
|
317
|
+
function toQueryString(query) {
|
|
318
|
+
const params = new URLSearchParams();
|
|
319
|
+
params.set("projectId", query.projectId);
|
|
320
|
+
if (query.status) params.set("status", query.status);
|
|
321
|
+
if (query.limit !== void 0) params.set("limit", String(query.limit));
|
|
322
|
+
if (query.offset !== void 0) params.set("offset", String(query.offset));
|
|
323
|
+
return params.toString();
|
|
324
|
+
}
|
|
325
|
+
var Campaigns = class {
|
|
326
|
+
constructor(http) {
|
|
327
|
+
this.http = http;
|
|
328
|
+
}
|
|
329
|
+
http;
|
|
330
|
+
async list(query) {
|
|
331
|
+
return this.http.get(`/campaigns?${toQueryString(query)}`);
|
|
332
|
+
}
|
|
333
|
+
async get(id) {
|
|
334
|
+
return this.http.get(`/campaigns/${encodeURIComponent(id)}`);
|
|
335
|
+
}
|
|
336
|
+
async create(input) {
|
|
337
|
+
return this.http.post("/campaigns", input);
|
|
338
|
+
}
|
|
339
|
+
async update(id, input) {
|
|
340
|
+
return this.http.patch(
|
|
341
|
+
`/campaigns/${encodeURIComponent(id)}`,
|
|
342
|
+
input
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
async send(id) {
|
|
346
|
+
return this.http.post(
|
|
347
|
+
`/campaigns/${encodeURIComponent(id)}/send`,
|
|
348
|
+
void 0
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
async pause(id) {
|
|
352
|
+
return this.http.post(
|
|
353
|
+
`/campaigns/${encodeURIComponent(id)}/pause`,
|
|
354
|
+
void 0
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
async resume(id) {
|
|
358
|
+
return this.http.post(
|
|
359
|
+
`/campaigns/${encodeURIComponent(id)}/resume`,
|
|
360
|
+
void 0
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
async cancel(id) {
|
|
364
|
+
return this.http.post(
|
|
365
|
+
`/campaigns/${encodeURIComponent(id)}/cancel`,
|
|
366
|
+
void 0
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
async duplicate(id) {
|
|
370
|
+
return this.http.post(
|
|
371
|
+
`/campaigns/${encodeURIComponent(id)}/duplicate`,
|
|
372
|
+
void 0
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
async delete(id) {
|
|
376
|
+
await this.http.delete(`/campaigns/${encodeURIComponent(id)}`);
|
|
377
|
+
}
|
|
378
|
+
async stats(id) {
|
|
379
|
+
return this.http.get(
|
|
380
|
+
`/campaigns/${encodeURIComponent(id)}/stats`
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
async providerStats(id) {
|
|
384
|
+
return this.http.get(
|
|
385
|
+
`/campaigns/${encodeURIComponent(id)}/provider-stats`
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
// src/contacts.ts
|
|
391
|
+
function toQueryString2(query) {
|
|
392
|
+
const params = new URLSearchParams();
|
|
393
|
+
params.set("projectId", query.projectId);
|
|
394
|
+
if (query.search) params.set("search", query.search);
|
|
395
|
+
if (query.tags) {
|
|
396
|
+
const tags = query.tags.filter(Boolean);
|
|
397
|
+
if (tags.length > 0) params.set("tags", tags.join(","));
|
|
398
|
+
}
|
|
399
|
+
if (query.tagMode) params.set("tagMode", query.tagMode);
|
|
400
|
+
if (query.limit !== void 0) params.set("limit", String(query.limit));
|
|
401
|
+
if (query.offset !== void 0) params.set("offset", String(query.offset));
|
|
402
|
+
return params.toString();
|
|
403
|
+
}
|
|
404
|
+
var Contacts = class {
|
|
405
|
+
constructor(http) {
|
|
406
|
+
this.http = http;
|
|
407
|
+
}
|
|
408
|
+
http;
|
|
409
|
+
async list(query) {
|
|
410
|
+
return this.http.get(
|
|
411
|
+
`/contacts?${toQueryString2(query)}`
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
async get(id) {
|
|
415
|
+
return this.http.get(`/contacts/${encodeURIComponent(id)}`);
|
|
416
|
+
}
|
|
417
|
+
async create(input) {
|
|
418
|
+
return this.http.post("/contacts", input);
|
|
419
|
+
}
|
|
420
|
+
async update(id, input) {
|
|
421
|
+
return this.http.patch(
|
|
422
|
+
`/contacts/${encodeURIComponent(id)}`,
|
|
423
|
+
input
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
async delete(id) {
|
|
427
|
+
await this.http.delete(`/contacts/${encodeURIComponent(id)}`);
|
|
428
|
+
}
|
|
429
|
+
async bulkCreate(input) {
|
|
430
|
+
return this.http.post("/contacts/bulk", input);
|
|
431
|
+
}
|
|
432
|
+
async tags(projectId) {
|
|
433
|
+
const params = new URLSearchParams();
|
|
434
|
+
params.set("projectId", projectId);
|
|
435
|
+
return this.http.get(`/contacts/tags?${params.toString()}`);
|
|
436
|
+
}
|
|
437
|
+
async lists(contactId) {
|
|
438
|
+
return this.http.get(
|
|
439
|
+
`/contacts/${encodeURIComponent(contactId)}/lists`
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
/** @deprecated Use `lists.addContacts` instead. */
|
|
443
|
+
async addToList(contactId, listId) {
|
|
444
|
+
await this.http.post(
|
|
445
|
+
`/lists/${encodeURIComponent(listId)}/contacts`,
|
|
446
|
+
{ contactIds: [contactId] }
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
/** @deprecated Use `lists.removeContact` instead. */
|
|
450
|
+
async removeFromList(contactId, listId) {
|
|
451
|
+
await this.http.delete(
|
|
452
|
+
`/lists/${encodeURIComponent(listId)}/contacts/${encodeURIComponent(contactId)}`
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
// src/lists.ts
|
|
458
|
+
function toQueryString3(query) {
|
|
459
|
+
const params = new URLSearchParams();
|
|
460
|
+
if (query.search) params.set("search", query.search);
|
|
461
|
+
if (query.limit !== void 0) params.set("limit", String(query.limit));
|
|
462
|
+
if (query.offset !== void 0) params.set("offset", String(query.offset));
|
|
463
|
+
return params.toString();
|
|
464
|
+
}
|
|
465
|
+
var Lists = class {
|
|
466
|
+
constructor(http) {
|
|
467
|
+
this.http = http;
|
|
468
|
+
}
|
|
469
|
+
http;
|
|
470
|
+
async list(projectId) {
|
|
471
|
+
const params = new URLSearchParams();
|
|
472
|
+
params.set("projectId", projectId);
|
|
473
|
+
return this.http.get(`/lists?${params.toString()}`);
|
|
474
|
+
}
|
|
475
|
+
async get(id) {
|
|
476
|
+
return this.http.get(`/lists/${encodeURIComponent(id)}`);
|
|
477
|
+
}
|
|
478
|
+
async create(input) {
|
|
479
|
+
return this.http.post("/lists", input);
|
|
480
|
+
}
|
|
481
|
+
async update(id, input) {
|
|
482
|
+
return this.http.patch(`/lists/${encodeURIComponent(id)}`, input);
|
|
483
|
+
}
|
|
484
|
+
async delete(id) {
|
|
485
|
+
await this.http.delete(`/lists/${encodeURIComponent(id)}`);
|
|
486
|
+
}
|
|
487
|
+
async listContacts(id, query = {}) {
|
|
488
|
+
return this.http.get(
|
|
489
|
+
`/lists/${encodeURIComponent(id)}/contacts?${toQueryString3(query)}`
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
async addContacts(id, contactIds) {
|
|
493
|
+
return this.http.post(
|
|
494
|
+
`/lists/${encodeURIComponent(id)}/contacts`,
|
|
495
|
+
{ contactIds }
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
async removeContact(id, contactId) {
|
|
499
|
+
await this.http.delete(
|
|
500
|
+
`/lists/${encodeURIComponent(id)}/contacts/${encodeURIComponent(contactId)}`
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
// src/sms.ts
|
|
506
|
+
function toQueryString4(query) {
|
|
507
|
+
const params = new URLSearchParams();
|
|
508
|
+
if (query.status) params.set("status", query.status);
|
|
509
|
+
if (query.limit !== void 0) params.set("limit", String(query.limit));
|
|
510
|
+
if (query.cursor) params.set("cursor", query.cursor);
|
|
511
|
+
return params.toString();
|
|
512
|
+
}
|
|
513
|
+
var Sms = class {
|
|
514
|
+
constructor(http) {
|
|
515
|
+
this.http = http;
|
|
516
|
+
}
|
|
517
|
+
http;
|
|
518
|
+
async send(input) {
|
|
519
|
+
return this.http.post("/v1/sms", input);
|
|
520
|
+
}
|
|
521
|
+
async get(id) {
|
|
522
|
+
return this.http.get(
|
|
523
|
+
`/v1/sms/${encodeURIComponent(id)}`
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
async list(query = {}) {
|
|
527
|
+
const qs = toQueryString4(query);
|
|
528
|
+
return this.http.get(`/v1/sms${qs ? `?${qs}` : ""}`);
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
// src/webhook.ts
|
|
533
|
+
async function verifyWebhookSignature(payload, signature, secret) {
|
|
534
|
+
const expected = signature.startsWith("sha256=") ? signature.slice(7) : signature;
|
|
535
|
+
const enc = new TextEncoder();
|
|
536
|
+
const key = await globalThis.crypto.subtle.importKey(
|
|
537
|
+
"raw",
|
|
538
|
+
enc.encode(secret),
|
|
539
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
540
|
+
false,
|
|
541
|
+
["sign"]
|
|
542
|
+
);
|
|
543
|
+
const mac = await globalThis.crypto.subtle.sign(
|
|
544
|
+
"HMAC",
|
|
545
|
+
key,
|
|
546
|
+
enc.encode(payload)
|
|
547
|
+
);
|
|
548
|
+
const computed = Array.from(new Uint8Array(mac)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
549
|
+
if (computed.length !== expected.length) return false;
|
|
550
|
+
let diff = 0;
|
|
551
|
+
for (let i = 0; i < computed.length; i++) {
|
|
552
|
+
diff |= computed.charCodeAt(i) ^ expected.charCodeAt(i);
|
|
553
|
+
}
|
|
554
|
+
return diff === 0;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// src/types.ts
|
|
558
|
+
var EMAIL_STATUSES = [
|
|
559
|
+
"queued",
|
|
560
|
+
"rendering",
|
|
561
|
+
"submitted_to_postfix",
|
|
562
|
+
"deferred",
|
|
563
|
+
"sent",
|
|
564
|
+
"delivered",
|
|
565
|
+
"bounced",
|
|
566
|
+
"rejected",
|
|
567
|
+
"failed",
|
|
568
|
+
"suppressed",
|
|
569
|
+
"cancelled",
|
|
570
|
+
"scheduled",
|
|
571
|
+
"quarantined"
|
|
572
|
+
];
|
|
573
|
+
var EMAIL_EVENT_TYPES = [
|
|
574
|
+
"queued",
|
|
575
|
+
"rendering_started",
|
|
576
|
+
"rendering_completed",
|
|
577
|
+
"submitted_to_postfix",
|
|
578
|
+
"deferred",
|
|
579
|
+
"sent",
|
|
580
|
+
"delivered",
|
|
581
|
+
"bounced",
|
|
582
|
+
"rejected",
|
|
583
|
+
"failed",
|
|
584
|
+
"suppressed",
|
|
585
|
+
"cancelled",
|
|
586
|
+
"retry_scheduled",
|
|
587
|
+
"open",
|
|
588
|
+
"click",
|
|
589
|
+
"quarantined"
|
|
590
|
+
];
|
|
591
|
+
var SMS_STATUSES = [
|
|
592
|
+
"queued",
|
|
593
|
+
"sending",
|
|
594
|
+
"sent",
|
|
595
|
+
"delivered",
|
|
596
|
+
"deferred",
|
|
597
|
+
"failed",
|
|
598
|
+
"suppressed"
|
|
599
|
+
];
|
|
600
|
+
|
|
601
|
+
// src/index.ts
|
|
65
602
|
var DevelEmail = class {
|
|
66
603
|
emails;
|
|
604
|
+
domains;
|
|
605
|
+
templates;
|
|
606
|
+
campaigns;
|
|
607
|
+
contacts;
|
|
608
|
+
lists;
|
|
609
|
+
sms;
|
|
67
610
|
constructor(config) {
|
|
68
|
-
|
|
611
|
+
const http = new HttpClient(config);
|
|
612
|
+
this.emails = new Emails(http);
|
|
613
|
+
this.domains = new Domains(http);
|
|
614
|
+
this.templates = new Templates(http);
|
|
615
|
+
this.campaigns = new Campaigns(http);
|
|
616
|
+
this.contacts = new Contacts(http);
|
|
617
|
+
this.lists = new Lists(http);
|
|
618
|
+
this.sms = new Sms(http);
|
|
69
619
|
}
|
|
70
620
|
};
|
|
71
621
|
// Annotate the CommonJS export names for ESM import in node:
|
|
72
622
|
0 && (module.exports = {
|
|
73
623
|
DevelEmail,
|
|
74
|
-
DevelEmailError
|
|
624
|
+
DevelEmailError,
|
|
625
|
+
EMAIL_EVENT_TYPES,
|
|
626
|
+
EMAIL_STATUSES,
|
|
627
|
+
SMS_STATUSES,
|
|
628
|
+
verifyWebhookSignature
|
|
75
629
|
});
|
|
76
630
|
//# sourceMappingURL=index.cjs.map
|