mailbreeze 0.1.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.cjs ADDED
@@ -0,0 +1,1003 @@
1
+ 'use strict';
2
+
3
+ // src/http/errors.ts
4
+ var MailBreezeError = class extends Error {
5
+ /** Error code for programmatic handling */
6
+ code;
7
+ /** HTTP status code (if applicable) */
8
+ statusCode;
9
+ /** Unique request ID for debugging with support */
10
+ requestId;
11
+ /** Additional error details (e.g., field-level validation errors) */
12
+ details;
13
+ constructor(message, code, statusCode, requestId, details) {
14
+ super(message);
15
+ this.name = "MailBreezeError";
16
+ this.code = code;
17
+ if (statusCode !== void 0) this.statusCode = statusCode;
18
+ if (requestId !== void 0) this.requestId = requestId;
19
+ if (details !== void 0) this.details = details;
20
+ if (Error.captureStackTrace) {
21
+ Error.captureStackTrace(this, this.constructor);
22
+ }
23
+ }
24
+ /**
25
+ * Serialize error to JSON-friendly object.
26
+ * Useful for logging and error reporting.
27
+ */
28
+ toJSON() {
29
+ return {
30
+ name: this.name,
31
+ message: this.message,
32
+ code: this.code,
33
+ statusCode: this.statusCode,
34
+ requestId: this.requestId,
35
+ details: this.details
36
+ };
37
+ }
38
+ };
39
+ var AuthenticationError = class extends MailBreezeError {
40
+ constructor(message, code = "AUTHENTICATION_ERROR", requestId) {
41
+ super(message, code, 401, requestId);
42
+ this.name = "AuthenticationError";
43
+ }
44
+ };
45
+ var ValidationError = class extends MailBreezeError {
46
+ constructor(message, code = "VALIDATION_ERROR", requestId, details) {
47
+ super(message, code, 400, requestId, details);
48
+ this.name = "ValidationError";
49
+ }
50
+ };
51
+ var NotFoundError = class extends MailBreezeError {
52
+ constructor(message, code = "NOT_FOUND", requestId) {
53
+ super(message, code, 404, requestId);
54
+ this.name = "NotFoundError";
55
+ }
56
+ };
57
+ var RateLimitError = class extends MailBreezeError {
58
+ /** Seconds to wait before retrying */
59
+ retryAfter;
60
+ constructor(message, code = "RATE_LIMIT_EXCEEDED", requestId, retryAfter) {
61
+ super(message, code, 429, requestId);
62
+ this.name = "RateLimitError";
63
+ if (retryAfter !== void 0) this.retryAfter = retryAfter;
64
+ }
65
+ toJSON() {
66
+ return {
67
+ ...super.toJSON(),
68
+ retryAfter: this.retryAfter
69
+ };
70
+ }
71
+ };
72
+ var ServerError = class extends MailBreezeError {
73
+ constructor(message, code = "SERVER_ERROR", statusCode = 500, requestId) {
74
+ super(message, code, statusCode, requestId);
75
+ this.name = "ServerError";
76
+ }
77
+ };
78
+ function createErrorFromResponse(statusCode, body, requestId, retryAfter) {
79
+ const message = body?.message ?? "Unknown error";
80
+ const code = body?.code ?? "UNKNOWN_ERROR";
81
+ const details = body?.details;
82
+ switch (statusCode) {
83
+ case 400:
84
+ return new ValidationError(message, code, requestId, details);
85
+ case 401:
86
+ return new AuthenticationError(message, code, requestId);
87
+ case 404:
88
+ return new NotFoundError(message, code, requestId);
89
+ case 429:
90
+ return new RateLimitError(message, code, requestId, retryAfter);
91
+ default:
92
+ if (statusCode >= 500) {
93
+ return new ServerError(message, code, statusCode, requestId);
94
+ }
95
+ return new MailBreezeError(message, code, statusCode, requestId, details);
96
+ }
97
+ }
98
+
99
+ // src/http/fetcher.ts
100
+ var SDK_VERSION = "0.1.0";
101
+ var Fetcher = class {
102
+ config;
103
+ constructor(config) {
104
+ this.config = {
105
+ ...config,
106
+ baseUrl: config.baseUrl.replace(/\/$/, "")
107
+ // Remove trailing slash
108
+ };
109
+ }
110
+ /**
111
+ * Make an HTTP request to the API.
112
+ *
113
+ * @param method - HTTP method
114
+ * @param path - API path (will be appended to baseUrl)
115
+ * @param body - Request body (for POST/PUT/PATCH)
116
+ * @param query - Query parameters
117
+ * @param options - Additional request options
118
+ * @returns Parsed response data
119
+ */
120
+ async request(method, path, body, query, options) {
121
+ const url = this.buildUrl(path, query);
122
+ const headers = this.buildHeaders(options?.idempotencyKey);
123
+ const timeout = options?.timeout ?? this.config.timeout;
124
+ let lastError;
125
+ let attempt = 0;
126
+ const maxAttempts = this.config.maxRetries + 1;
127
+ while (attempt < maxAttempts) {
128
+ attempt++;
129
+ try {
130
+ const result = await this.executeRequest(method, url, headers, body, timeout);
131
+ return result;
132
+ } catch (error) {
133
+ lastError = error;
134
+ if (!this.isRetryable(lastError, error)) {
135
+ throw lastError;
136
+ }
137
+ if (attempt >= maxAttempts) {
138
+ throw lastError;
139
+ }
140
+ const delay = this.getRetryDelay(lastError, attempt);
141
+ await this.sleep(delay);
142
+ }
143
+ }
144
+ throw lastError ?? new MailBreezeError("Unexpected error during request", "UNEXPECTED_ERROR");
145
+ }
146
+ async executeRequest(method, url, headers, body, timeout) {
147
+ const controller = new AbortController();
148
+ const timeoutId = timeout ? setTimeout(() => controller.abort(), timeout) : void 0;
149
+ try {
150
+ const fetchOptions = {
151
+ method,
152
+ headers,
153
+ signal: controller.signal
154
+ };
155
+ if (body && method !== "GET" && method !== "HEAD") {
156
+ fetchOptions.body = JSON.stringify(body);
157
+ }
158
+ const response = await fetch(url, fetchOptions);
159
+ return await this.handleResponse(response);
160
+ } catch (error) {
161
+ if (error instanceof Error && error.name === "AbortError") {
162
+ throw new MailBreezeError("Request timeout", "TIMEOUT_ERROR", 0);
163
+ }
164
+ if (error instanceof Error && !(error instanceof MailBreezeError)) {
165
+ throw new ServerError(`Network error: ${error.message}`, "NETWORK_ERROR", 0);
166
+ }
167
+ throw error;
168
+ } finally {
169
+ if (timeoutId !== void 0) {
170
+ clearTimeout(timeoutId);
171
+ }
172
+ }
173
+ }
174
+ async handleResponse(response) {
175
+ const requestId = response.headers.get("X-Request-Id") ?? void 0;
176
+ const retryAfter = response.headers.get("Retry-After");
177
+ const retryAfterSeconds = retryAfter ? Number.parseInt(retryAfter, 10) : void 0;
178
+ if (response.status === 204) {
179
+ return void 0;
180
+ }
181
+ let body;
182
+ try {
183
+ body = await response.json();
184
+ } catch {
185
+ if (!response.ok) {
186
+ throw createErrorFromResponse(response.status, void 0, requestId);
187
+ }
188
+ return void 0;
189
+ }
190
+ if (!body.success) {
191
+ const errorBody = body.error;
192
+ const statusCode = response.ok ? 400 : response.status;
193
+ throw createErrorFromResponse(statusCode, errorBody, requestId, retryAfterSeconds);
194
+ }
195
+ if (!response.ok) {
196
+ throw createErrorFromResponse(response.status, void 0, requestId, retryAfterSeconds);
197
+ }
198
+ return body.data;
199
+ }
200
+ buildUrl(path, query) {
201
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
202
+ const url = new URL(`${this.config.baseUrl}${normalizedPath}`);
203
+ if (query) {
204
+ for (const [key, value] of Object.entries(query)) {
205
+ if (value !== void 0 && value !== null) {
206
+ url.searchParams.append(key, String(value));
207
+ }
208
+ }
209
+ }
210
+ return url.toString();
211
+ }
212
+ buildHeaders(idempotencyKey) {
213
+ const headers = {
214
+ "Content-Type": "application/json",
215
+ "User-Agent": `mailbreeze-js/${SDK_VERSION}`
216
+ };
217
+ if (this.config.authStyle === "bearer") {
218
+ headers.Authorization = `Bearer ${this.config.apiKey}`;
219
+ } else {
220
+ headers["X-API-Key"] = this.config.apiKey;
221
+ }
222
+ if (idempotencyKey) {
223
+ if (/[\r\n]/.test(idempotencyKey)) {
224
+ throw new MailBreezeError("Invalid idempotency key: contains invalid characters", "INVALID_IDEMPOTENCY_KEY");
225
+ }
226
+ headers["X-Idempotency-Key"] = idempotencyKey;
227
+ }
228
+ return headers;
229
+ }
230
+ isRetryable(error, originalError) {
231
+ if (originalError instanceof Error && originalError.name === "AbortError") {
232
+ return false;
233
+ }
234
+ if (error.statusCode === 429 || error.statusCode !== void 0 && error.statusCode >= 500) {
235
+ return true;
236
+ }
237
+ if (error.statusCode === 0 && error.code === "NETWORK_ERROR") {
238
+ return true;
239
+ }
240
+ return false;
241
+ }
242
+ getRetryDelay(error, attempt) {
243
+ if (error instanceof RateLimitError && error.retryAfter) {
244
+ return error.retryAfter * 1e3;
245
+ }
246
+ return 2 ** (attempt - 1) * 1e3;
247
+ }
248
+ sleep(ms) {
249
+ return new Promise((resolve) => setTimeout(resolve, ms));
250
+ }
251
+ };
252
+
253
+ // src/resources/base.ts
254
+ var BaseResource = class {
255
+ fetcher;
256
+ domainId;
257
+ constructor(fetcher, domainId) {
258
+ this.fetcher = fetcher;
259
+ if (domainId !== void 0) this.domainId = domainId;
260
+ }
261
+ /**
262
+ * Make a GET request.
263
+ */
264
+ _get(path, query, options) {
265
+ return this.fetcher.request("GET", this.buildPath(path), void 0, this.addDomainId(query), options);
266
+ }
267
+ /**
268
+ * Make a POST request.
269
+ */
270
+ _post(path, body, query, options) {
271
+ return this.fetcher.request(
272
+ "POST",
273
+ this.buildPath(path),
274
+ body,
275
+ this.addDomainId(query),
276
+ options
277
+ );
278
+ }
279
+ /**
280
+ * Make a PUT request.
281
+ */
282
+ _put(path, body, query, options) {
283
+ return this.fetcher.request(
284
+ "PUT",
285
+ this.buildPath(path),
286
+ body,
287
+ this.addDomainId(query),
288
+ options
289
+ );
290
+ }
291
+ /**
292
+ * Make a PATCH request.
293
+ */
294
+ _patch(path, body, query, options) {
295
+ return this.fetcher.request(
296
+ "PATCH",
297
+ this.buildPath(path),
298
+ body,
299
+ this.addDomainId(query),
300
+ options
301
+ );
302
+ }
303
+ /**
304
+ * Make a DELETE request.
305
+ */
306
+ _delete(path, query, options) {
307
+ return this.fetcher.request("DELETE", this.buildPath(path), void 0, this.addDomainId(query), options);
308
+ }
309
+ /**
310
+ * Build the full path including any base path for the resource.
311
+ */
312
+ buildPath(path) {
313
+ return path;
314
+ }
315
+ /**
316
+ * Add domain ID to query params if configured.
317
+ */
318
+ addDomainId(query) {
319
+ if (!this.domainId) {
320
+ return query;
321
+ }
322
+ return { ...query, domainId: this.domainId };
323
+ }
324
+ /**
325
+ * Helper to extract pagination from list response.
326
+ */
327
+ extractPaginatedList(response) {
328
+ if (Array.isArray(response)) {
329
+ return {
330
+ data: response,
331
+ pagination: {
332
+ page: 1,
333
+ limit: response.length,
334
+ total: response.length,
335
+ totalPages: 1,
336
+ hasNext: false,
337
+ hasPrev: false
338
+ }
339
+ };
340
+ }
341
+ return {
342
+ data: response.data,
343
+ pagination: response.pagination
344
+ };
345
+ }
346
+ /**
347
+ * Convert list params to query object.
348
+ */
349
+ listParamsToQuery(params) {
350
+ if (!params) return void 0;
351
+ const query = {};
352
+ if (params.page !== void 0) query.page = params.page;
353
+ if (params.limit !== void 0) query.limit = params.limit;
354
+ return Object.keys(query).length > 0 ? query : void 0;
355
+ }
356
+ };
357
+
358
+ // src/resources/attachments.ts
359
+ var Attachments = class extends BaseResource {
360
+ /**
361
+ * Create a presigned URL for uploading an attachment.
362
+ *
363
+ * @param params - Attachment metadata
364
+ * @returns Upload URL and attachment ID
365
+ *
366
+ * @example
367
+ * ```ts
368
+ * const { attachmentId, uploadUrl, uploadToken, expiresAt } =
369
+ * await mailbreeze.attachments.createUpload({
370
+ * fileName: "document.pdf",
371
+ * contentType: "application/pdf",
372
+ * fileSize: 2048000,
373
+ * });
374
+ * ```
375
+ */
376
+ async createUpload(params) {
377
+ return this._post("/attachments/upload", params);
378
+ }
379
+ /**
380
+ * Confirm that an attachment has been uploaded.
381
+ *
382
+ * Must be called after uploading the file to the presigned URL.
383
+ * The attachment is only available for use after confirmation.
384
+ *
385
+ * @param params - Confirmation parameters including upload token
386
+ * @returns Confirmed attachment record
387
+ *
388
+ * @example
389
+ * ```ts
390
+ * const attachment = await mailbreeze.attachments.confirm({
391
+ * uploadToken: "token_xxx",
392
+ * });
393
+ * console.log(attachment.status); // "uploaded"
394
+ * ```
395
+ */
396
+ async confirm(params) {
397
+ return this._post("/attachments/confirm", params);
398
+ }
399
+ };
400
+
401
+ // src/resources/automations.ts
402
+ var Automations = class extends BaseResource {
403
+ /**
404
+ * Enrollments sub-resource for listing and cancelling.
405
+ */
406
+ enrollments;
407
+ constructor(fetcher, domainId) {
408
+ super(fetcher, domainId);
409
+ this.enrollments = new AutomationEnrollments(fetcher, domainId);
410
+ }
411
+ /**
412
+ * Enroll a contact in an automation.
413
+ *
414
+ * @param params - Enrollment parameters
415
+ * @returns Enrollment result
416
+ *
417
+ * @example
418
+ * ```ts
419
+ * const enrollment = await mailbreeze.automations.enroll({
420
+ * automationId: "auto_welcome",
421
+ * contactId: "contact_xxx",
422
+ * variables: { firstName: "John" },
423
+ * });
424
+ * console.log(enrollment.enrollmentId);
425
+ * ```
426
+ */
427
+ async enroll(params) {
428
+ return this._post(`/automations/${params.automationId}/enroll`, {
429
+ contactId: params.contactId,
430
+ variables: params.variables
431
+ });
432
+ }
433
+ };
434
+ var AutomationEnrollments = class extends BaseResource {
435
+ /**
436
+ * List automation enrollments.
437
+ *
438
+ * @param params - Filter and pagination options
439
+ * @returns Paginated list of enrollments
440
+ *
441
+ * @example
442
+ * ```ts
443
+ * const { data, pagination } = await mailbreeze.automations.enrollments.list({
444
+ * automationId: "auto_xxx",
445
+ * status: "active",
446
+ * });
447
+ * ```
448
+ */
449
+ async list(params) {
450
+ const query = {
451
+ ...this.listParamsToQuery(params)
452
+ };
453
+ if (params?.automationId) query.automationId = params.automationId;
454
+ if (params?.status) query.status = params.status;
455
+ const response = await this._get("/automation-enrollments", Object.keys(query).length > 0 ? query : void 0);
456
+ return this.extractPaginatedList(response);
457
+ }
458
+ /**
459
+ * Cancel an enrollment.
460
+ *
461
+ * The contact will stop receiving emails from this automation.
462
+ *
463
+ * @param enrollmentId - Enrollment ID
464
+ * @returns Cancellation result
465
+ *
466
+ * @example
467
+ * ```ts
468
+ * const result = await mailbreeze.automations.enrollments.cancel("enroll_xxx");
469
+ * console.log(result.cancelled); // true
470
+ * ```
471
+ */
472
+ async cancel(enrollmentId) {
473
+ return this._post(`/automation-enrollments/${enrollmentId}/cancel`, {});
474
+ }
475
+ };
476
+
477
+ // src/resources/contacts.ts
478
+ var Contacts = class extends BaseResource {
479
+ listId;
480
+ constructor(fetcher, listId, domainId) {
481
+ super(fetcher, domainId);
482
+ this.listId = listId;
483
+ }
484
+ buildPath(path) {
485
+ return `/contact-lists/${this.listId}/contacts${path}`;
486
+ }
487
+ /**
488
+ * Create a new contact in the list.
489
+ *
490
+ * @param params - Contact data
491
+ * @returns Created contact record
492
+ *
493
+ * @example
494
+ * ```ts
495
+ * const contact = await contacts.create({
496
+ * email: "user@example.com",
497
+ * firstName: "Jane",
498
+ * lastName: "Smith",
499
+ * customFields: { plan: "pro" },
500
+ * });
501
+ * ```
502
+ */
503
+ async create(params) {
504
+ return this._post("", params);
505
+ }
506
+ /**
507
+ * List contacts in the list.
508
+ *
509
+ * @param params - Filter and pagination options
510
+ * @returns Paginated list of contacts
511
+ *
512
+ * @example
513
+ * ```ts
514
+ * const { data, pagination } = await contacts.list({
515
+ * status: "active",
516
+ * page: 1,
517
+ * limit: 50,
518
+ * });
519
+ * ```
520
+ */
521
+ async list(params) {
522
+ const query = {
523
+ ...this.listParamsToQuery(params)
524
+ };
525
+ if (params?.status) query.status = params.status;
526
+ const response = await this._get(
527
+ "",
528
+ Object.keys(query).length > 0 ? query : void 0
529
+ );
530
+ return this.extractPaginatedList(response);
531
+ }
532
+ /**
533
+ * Get a contact by ID.
534
+ *
535
+ * @param id - Contact ID
536
+ * @returns Contact record
537
+ *
538
+ * @example
539
+ * ```ts
540
+ * const contact = await contacts.get("contact_xxx");
541
+ * ```
542
+ */
543
+ async get(id) {
544
+ return this._get(`/${id}`);
545
+ }
546
+ /**
547
+ * Update a contact.
548
+ *
549
+ * @param id - Contact ID
550
+ * @param params - Fields to update
551
+ * @returns Updated contact record
552
+ *
553
+ * @example
554
+ * ```ts
555
+ * const contact = await contacts.update("contact_xxx", {
556
+ * firstName: "Updated Name",
557
+ * customFields: { plan: "enterprise" },
558
+ * });
559
+ * ```
560
+ */
561
+ async update(id, params) {
562
+ return this._put(`/${id}`, params);
563
+ }
564
+ /**
565
+ * Delete a contact.
566
+ *
567
+ * @param id - Contact ID
568
+ * @returns void
569
+ *
570
+ * @example
571
+ * ```ts
572
+ * await contacts.delete("contact_xxx");
573
+ * ```
574
+ */
575
+ async delete(id) {
576
+ await this._delete(`/${id}`);
577
+ }
578
+ /**
579
+ * Suppress a contact.
580
+ *
581
+ * Suppressed contacts will not receive any emails.
582
+ * This is different from unsubscribing - suppression is
583
+ * typically used for bounces, complaints, or manual removal.
584
+ *
585
+ * @param id - Contact ID
586
+ * @param reason - Reason for suppression
587
+ * @returns void
588
+ *
589
+ * @example
590
+ * ```ts
591
+ * await contacts.suppress("contact_xxx", "manual");
592
+ * ```
593
+ */
594
+ async suppress(id, reason) {
595
+ await this._post(`/${id}/suppress`, { reason });
596
+ }
597
+ };
598
+
599
+ // src/resources/emails.ts
600
+ var Emails = class extends BaseResource {
601
+ /**
602
+ * Send an email.
603
+ *
604
+ * @param params - Email parameters
605
+ * @returns Send result with email ID and status
606
+ *
607
+ * @example
608
+ * ```ts
609
+ * const result = await mailbreeze.emails.send({
610
+ * from: "hello@yourdomain.com",
611
+ * to: "user@example.com",
612
+ * subject: "Hello",
613
+ * html: "<p>Hello World!</p>",
614
+ * });
615
+ * console.log(result.id); // email_xxx
616
+ * ```
617
+ */
618
+ async send(params) {
619
+ const { idempotencyKey, ...body } = params;
620
+ const normalizedBody = {
621
+ ...body,
622
+ to: Array.isArray(body.to) ? body.to : [body.to],
623
+ cc: body.cc ? Array.isArray(body.cc) ? body.cc : [body.cc] : void 0,
624
+ bcc: body.bcc ? Array.isArray(body.bcc) ? body.bcc : [body.bcc] : void 0
625
+ };
626
+ return this._post(
627
+ "/emails",
628
+ normalizedBody,
629
+ void 0,
630
+ idempotencyKey ? { idempotencyKey } : void 0
631
+ );
632
+ }
633
+ /**
634
+ * List sent emails with optional filtering.
635
+ *
636
+ * @param params - Filter and pagination options
637
+ * @returns Paginated list of emails
638
+ *
639
+ * @example
640
+ * ```ts
641
+ * const { data, pagination } = await mailbreeze.emails.list({
642
+ * status: "delivered",
643
+ * page: 1,
644
+ * limit: 20,
645
+ * });
646
+ * ```
647
+ */
648
+ async list(params) {
649
+ const query = {
650
+ ...this.listParamsToQuery(params)
651
+ };
652
+ if (params?.status) query.status = params.status;
653
+ if (params?.to) query.to = params.to;
654
+ if (params?.from) query.from = params.from;
655
+ if (params?.startDate) query.startDate = params.startDate;
656
+ if (params?.endDate) query.endDate = params.endDate;
657
+ const response = await this._get(
658
+ "/emails",
659
+ Object.keys(query).length > 0 ? query : void 0
660
+ );
661
+ return this.extractPaginatedList(response);
662
+ }
663
+ /**
664
+ * Get a single email by ID.
665
+ *
666
+ * @param id - Email ID
667
+ * @returns Email record
668
+ *
669
+ * @example
670
+ * ```ts
671
+ * const email = await mailbreeze.emails.get("email_xxx");
672
+ * console.log(email.status); // "delivered"
673
+ * ```
674
+ */
675
+ async get(id) {
676
+ return this._get(`/emails/${id}`);
677
+ }
678
+ /**
679
+ * Get email statistics for the domain.
680
+ *
681
+ * @returns Email statistics including delivery rates
682
+ *
683
+ * @example
684
+ * ```ts
685
+ * const stats = await mailbreeze.emails.stats();
686
+ * console.log(stats.deliveryRate); // 0.98
687
+ * ```
688
+ */
689
+ async stats() {
690
+ return this._get("/emails/stats");
691
+ }
692
+ };
693
+
694
+ // src/resources/lists.ts
695
+ var Lists = class extends BaseResource {
696
+ /**
697
+ * Create a new contact list.
698
+ *
699
+ * @param params - List configuration
700
+ * @returns Created list record
701
+ *
702
+ * @example
703
+ * ```ts
704
+ * const list = await mailbreeze.lists.create({
705
+ * name: "VIP Customers",
706
+ * customFields: [
707
+ * { key: "tier", label: "Tier", type: "select", options: ["gold", "platinum"] },
708
+ * ],
709
+ * });
710
+ * ```
711
+ */
712
+ async create(params) {
713
+ return this._post("/contact-lists", params);
714
+ }
715
+ /**
716
+ * List all contact lists.
717
+ *
718
+ * @param params - Pagination options
719
+ * @returns Paginated list of contact lists
720
+ *
721
+ * @example
722
+ * ```ts
723
+ * const { data, pagination } = await mailbreeze.lists.list({ page: 1, limit: 10 });
724
+ * ```
725
+ */
726
+ async list(params) {
727
+ const response = await this._get(
728
+ "/contact-lists",
729
+ this.listParamsToQuery(params)
730
+ );
731
+ return this.extractPaginatedList(response);
732
+ }
733
+ /**
734
+ * Get a contact list by ID.
735
+ *
736
+ * @param id - List ID
737
+ * @returns Contact list record
738
+ *
739
+ * @example
740
+ * ```ts
741
+ * const list = await mailbreeze.lists.get("list_xxx");
742
+ * ```
743
+ */
744
+ async get(id) {
745
+ return this._get(`/contact-lists/${id}`);
746
+ }
747
+ /**
748
+ * Update a contact list.
749
+ *
750
+ * @param id - List ID
751
+ * @param params - Fields to update
752
+ * @returns Updated list record
753
+ *
754
+ * @example
755
+ * ```ts
756
+ * const list = await mailbreeze.lists.update("list_xxx", {
757
+ * name: "Updated List Name",
758
+ * });
759
+ * ```
760
+ */
761
+ async update(id, params) {
762
+ return this._patch(`/contact-lists/${id}`, params);
763
+ }
764
+ /**
765
+ * Delete a contact list.
766
+ *
767
+ * Warning: This will also delete all contacts in the list.
768
+ *
769
+ * @param id - List ID
770
+ * @returns void
771
+ *
772
+ * @example
773
+ * ```ts
774
+ * await mailbreeze.lists.delete("list_xxx");
775
+ * ```
776
+ */
777
+ async delete(id) {
778
+ await this._delete(`/contact-lists/${id}`);
779
+ }
780
+ /**
781
+ * Get statistics for a contact list.
782
+ *
783
+ * @param id - List ID
784
+ * @returns List statistics
785
+ *
786
+ * @example
787
+ * ```ts
788
+ * const stats = await mailbreeze.lists.stats("list_xxx");
789
+ * console.log(`Active: ${stats.activeContacts}, Bounced: ${stats.bouncedContacts}`);
790
+ * ```
791
+ */
792
+ async stats(id) {
793
+ return this._get(`/contact-lists/${id}/stats`);
794
+ }
795
+ };
796
+
797
+ // src/resources/verification.ts
798
+ var Verification = class extends BaseResource {
799
+ /**
800
+ * Verify a single email address.
801
+ *
802
+ * This is a synchronous operation - the result is returned immediately.
803
+ * Results are cached for 24 hours.
804
+ *
805
+ * @param email - Email address to verify
806
+ * @returns Verification result
807
+ *
808
+ * @example
809
+ * ```ts
810
+ * const result = await mailbreeze.verification.verify("test@example.com");
811
+ * console.log(result.isValid); // true
812
+ * console.log(result.result); // "valid"
813
+ * console.log(result.details?.isDisposable); // false
814
+ * ```
815
+ */
816
+ async verify(email) {
817
+ return this._post("/email-verification/single", { email });
818
+ }
819
+ /**
820
+ * Start batch verification.
821
+ *
822
+ * Submits a batch of emails for verification. For large batches,
823
+ * results are processed asynchronously - poll with `get()` for status.
824
+ *
825
+ * If all emails are cached, results are returned immediately.
826
+ *
827
+ * @param params - Batch parameters including emails array
828
+ * @returns Batch verification result with ID for polling
829
+ *
830
+ * @example
831
+ * ```ts
832
+ * const batch = await mailbreeze.verification.batch({
833
+ * emails: ["user1@example.com", "user2@example.com", "user3@example.com"],
834
+ * });
835
+ *
836
+ * if (batch.results) {
837
+ * // All cached - results available immediately
838
+ * console.log(batch.results);
839
+ * } else {
840
+ * // Poll for results
841
+ * const status = await mailbreeze.verification.get(batch.verificationId);
842
+ * }
843
+ * ```
844
+ */
845
+ async batch(params) {
846
+ return this._post("/email-verification/batch", params);
847
+ }
848
+ /**
849
+ * Get verification batch status and results.
850
+ *
851
+ * @param verificationId - Verification batch ID
852
+ * @returns Current status and results when complete
853
+ *
854
+ * @example
855
+ * ```ts
856
+ * const status = await mailbreeze.verification.get("ver_xxx");
857
+ * if (status.status === "completed") {
858
+ * console.log(status.results);
859
+ * console.log(status.analytics);
860
+ * }
861
+ * ```
862
+ */
863
+ async get(verificationId) {
864
+ return this._get(`/email-verification/${verificationId}`, {
865
+ includeResults: true
866
+ });
867
+ }
868
+ /**
869
+ * List verification batches.
870
+ *
871
+ * @param params - Filter and pagination options
872
+ * @returns Paginated list of verification batches
873
+ *
874
+ * @example
875
+ * ```ts
876
+ * const { data, pagination } = await mailbreeze.verification.list({
877
+ * status: "completed",
878
+ * page: 1,
879
+ * });
880
+ * ```
881
+ */
882
+ async list(params) {
883
+ const query = {
884
+ ...this.listParamsToQuery(params)
885
+ };
886
+ if (params?.status) query.status = params.status;
887
+ const response = await this._get("/email-verification", Object.keys(query).length > 0 ? query : void 0);
888
+ return this.extractPaginatedList(response);
889
+ }
890
+ /**
891
+ * Get verification statistics.
892
+ *
893
+ * @returns Aggregate verification stats
894
+ *
895
+ * @example
896
+ * ```ts
897
+ * const stats = await mailbreeze.verification.stats();
898
+ * console.log(`Verified: ${stats.totalVerified}, Valid: ${stats.valid}`);
899
+ * ```
900
+ */
901
+ async stats() {
902
+ return this._get("/email-verification/stats");
903
+ }
904
+ };
905
+
906
+ // src/client.ts
907
+ var DEFAULT_BASE_URL = "https://api.mailbreeze.com";
908
+ var DEFAULT_TIMEOUT = 3e4;
909
+ var DEFAULT_MAX_RETRIES = 3;
910
+ var MailBreeze = class {
911
+ /**
912
+ * Email sending and management.
913
+ */
914
+ emails;
915
+ /**
916
+ * Email attachment handling.
917
+ */
918
+ attachments;
919
+ /**
920
+ * Contact list management.
921
+ */
922
+ lists;
923
+ /**
924
+ * Email verification services.
925
+ */
926
+ verification;
927
+ /**
928
+ * Automation enrollment management.
929
+ */
930
+ automations;
931
+ fetcher;
932
+ domainId;
933
+ /**
934
+ * Create a new MailBreeze client.
935
+ *
936
+ * @param config - Client configuration
937
+ *
938
+ * @example
939
+ * ```ts
940
+ * // Basic usage
941
+ * const mailbreeze = new MailBreeze({
942
+ * apiKey: "sk_live_xxx",
943
+ * });
944
+ *
945
+ * // With custom options
946
+ * const mailbreeze = new MailBreeze({
947
+ * apiKey: "sk_live_xxx",
948
+ * baseUrl: "https://api.eu.mailbreeze.com",
949
+ * timeout: 60000,
950
+ * maxRetries: 5,
951
+ * });
952
+ * ```
953
+ */
954
+ constructor(config) {
955
+ if (!config.apiKey) {
956
+ throw new Error("API key is required");
957
+ }
958
+ this.fetcher = new Fetcher({
959
+ apiKey: config.apiKey,
960
+ baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
961
+ timeout: config.timeout ?? DEFAULT_TIMEOUT,
962
+ maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,
963
+ authStyle: config.authStyle ?? "header"
964
+ });
965
+ this.emails = new Emails(this.fetcher, this.domainId);
966
+ this.attachments = new Attachments(this.fetcher, this.domainId);
967
+ this.lists = new Lists(this.fetcher, this.domainId);
968
+ this.verification = new Verification(this.fetcher, this.domainId);
969
+ this.automations = new Automations(this.fetcher, this.domainId);
970
+ }
971
+ /**
972
+ * Get a contacts resource for a specific list.
973
+ *
974
+ * @param listId - Contact list ID
975
+ * @returns Contacts resource bound to the list
976
+ *
977
+ * @example
978
+ * ```ts
979
+ * const contacts = mailbreeze.contacts("list_xxx");
980
+ *
981
+ * // Create a contact in this list
982
+ * const contact = await contacts.create({
983
+ * email: "user@example.com",
984
+ * });
985
+ *
986
+ * // List contacts in this list
987
+ * const { data } = await contacts.list();
988
+ * ```
989
+ */
990
+ contacts(listId) {
991
+ return new Contacts(this.fetcher, listId, this.domainId);
992
+ }
993
+ };
994
+
995
+ exports.AuthenticationError = AuthenticationError;
996
+ exports.MailBreeze = MailBreeze;
997
+ exports.MailBreezeError = MailBreezeError;
998
+ exports.NotFoundError = NotFoundError;
999
+ exports.RateLimitError = RateLimitError;
1000
+ exports.ServerError = ServerError;
1001
+ exports.ValidationError = ValidationError;
1002
+ //# sourceMappingURL=index.cjs.map
1003
+ //# sourceMappingURL=index.cjs.map