mailchannels-sdk 0.6.1 → 0.7.1

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.
@@ -50,6 +50,12 @@ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
50
50
  ErrorCode2[ErrorCode2["UnprocessableEntity"] = 422] = "UnprocessableEntity";
51
51
  return ErrorCode2;
52
52
  })(ErrorCode || {});
53
+ const createError = (message, statusCode = null) => {
54
+ return {
55
+ message,
56
+ statusCode
57
+ };
58
+ };
53
59
  const getStatusError = (response, errors = {}) => {
54
60
  const statusText = errors[response.status] || "Unknown error.";
55
61
  const payload = response._data ?? response.data;
@@ -61,12 +67,11 @@ const getStatusError = (response, errors = {}) => {
61
67
  } else if (Array.isArray(payload?.errors) && payload.errors?.length) {
62
68
  details = payload.errors.join(", ");
63
69
  }
64
- return details ? `${statusText} ${details}` : statusText;
70
+ return createError(details ? `${statusText} ${details}` : statusText, response.status ?? null);
71
+ };
72
+ const getResultError = (e, fallback) => {
73
+ return createError(e instanceof Error ? e.message : fallback);
65
74
  };
66
- function getResultError(result, error, fallback) {
67
- if (result.error) return result.error;
68
- return error instanceof Error ? error.message : fallback;
69
- }
70
75
 
71
76
  const isValidEmail = (email) => {
72
77
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
@@ -125,13 +130,13 @@ const clean = (data) => {
125
130
  };
126
131
  const validateLimit = (limit, max) => {
127
132
  if (typeof limit === "number" && (limit < 1 || max && limit > max)) {
128
- return "The limit value " + (max ? `must be between 1 and ${max}.` : "is invalid. Only positive values are allowed.");
133
+ return createError("The limit value " + (max ? `must be between 1 and ${max}.` : "is invalid. Only positive values are allowed."));
129
134
  }
130
135
  return null;
131
136
  };
132
137
  const validateOffset = (offset) => {
133
138
  if (typeof offset === "number" && offset < 0) {
134
- return "Offset must be greater than or equal to 0.";
139
+ return createError("Offset must be greater than or equal to 0.");
135
140
  }
136
141
  return null;
137
142
  };
@@ -143,37 +148,22 @@ class Emails {
143
148
  constructor(mailchannels) {
144
149
  this.mailchannels = mailchannels;
145
150
  }
146
- /**
147
- * Send an email using MailChannels Email API.
148
- * @param options - The email options to send.
149
- * @param dryRun - When set to `true`, the message will not be sent. Instead, the fully rendered message will be returned in the `data` property of the response. The default value is `false`.
150
- * @example
151
- * ```ts
152
- * const mailchannels = new MailChannels('your-api-key')
153
- * const { success, data } = await mailchannels.emails.send({
154
- * to: 'to@example.com',
155
- * from: 'from@example.com',
156
- * subject: 'Test',
157
- * html: 'Test'
158
- * })
159
- * ```
160
- */
161
- async send(options, dryRun = false) {
151
+ async _sendEmail(options, flags) {
152
+ let error = null;
162
153
  const { cc, bcc, from, to, html, text, mustaches, dkim } = options;
163
- const result = { success: false, data: null, error: null };
164
154
  const parsedFrom = parseRecipient(from);
165
155
  if (!parsedFrom || !parsedFrom.email) {
166
- result.error = "No sender provided. Use the `from` option to specify a sender";
167
- return result;
156
+ error = createError("No sender provided. Use the `from` option to specify a sender");
157
+ return { success: false, data: null, error };
168
158
  }
169
159
  const parsedTo = parseArrayRecipients(to);
170
160
  if (!parsedTo || !parsedTo.length) {
171
- result.error = "No recipients provided. Use the `to` option to specify at least one recipient";
172
- return result;
161
+ error = createError("No recipients provided. Use the `to` option to specify at least one recipient");
162
+ return { success: false, data: null, error };
173
163
  }
174
164
  if (!text && !html) {
175
- result.error = "No email content provided";
176
- return result;
165
+ error = createError("No email content provided");
166
+ return { success: false, data: null, error };
177
167
  }
178
168
  const content = [];
179
169
  const template_type = mustaches ? "mustache" : void 0;
@@ -202,36 +192,81 @@ class Emails {
202
192
  } : void 0,
203
193
  transactional: options.transactional
204
194
  };
205
- const response = await this.mailchannels.post("/tx/v1/send", {
206
- query: { "dry-run": dryRun },
195
+ const endpoint = flags.async ? "/tx/v1/send-async" : "/tx/v1/send";
196
+ const response = await this.mailchannels.post(endpoint, {
197
+ query: { "dry-run": flags.dryRun },
207
198
  body: payload,
208
- onResponse: async ({ response: response2 }) => {
209
- if (response2.ok) {
210
- result.success = true;
211
- return;
212
- }
213
- result.error = getStatusError(response2, {
199
+ onResponseError: async ({ response: response2 }) => {
200
+ error = getStatusError(response2, {
214
201
  [ErrorCode.BadRequest]: "Bad Request.",
215
202
  [ErrorCode.Forbidden]: "User does not have access to this feature.",
216
203
  [ErrorCode.PayloadTooLarge]: "The total message size should not exceed 30MB. This includes the message itself, headers, and the combined size of any attachments."
217
204
  });
218
205
  }
219
- }).catch((error) => {
220
- result.error = getResultError(result, error, "Failed to send email.");
206
+ }).catch((e) => {
207
+ error ||= getResultError(e, flags.async ? "Failed to queue email." : "Failed to send email.");
221
208
  return null;
222
209
  });
223
- if (!response) return result;
224
- result.data = clean({
225
- rendered: response.data,
226
- requestId: response.request_id,
227
- results: response.results?.map((result2) => ({
228
- index: result2.index,
229
- messageId: result2.message_id,
230
- reason: result2.reason,
231
- status: result2.status
210
+ if (!response) return { success: false, data: null, error };
211
+ if (flags.async) {
212
+ const asyncResponse = response;
213
+ const data2 = clean({
214
+ queuedAt: asyncResponse.queued_at,
215
+ requestId: asyncResponse.request_id
216
+ });
217
+ return { data: data2, error: null };
218
+ }
219
+ const syncResponse = response;
220
+ const data = clean({
221
+ rendered: syncResponse.data,
222
+ requestId: syncResponse.request_id,
223
+ results: syncResponse.results?.map((result) => ({
224
+ index: result.index,
225
+ messageId: result.message_id,
226
+ reason: result.reason,
227
+ status: result.status
232
228
  }))
233
229
  });
234
- return result;
230
+ return { success: !!data, data, error: null };
231
+ }
232
+ /**
233
+ * Sends an email message to one or more recipients.
234
+ * @param options - The email options to send.
235
+ * @param dryRun - When set to `true`, the message will not be sent. Instead, the fully rendered message will be returned in the `data` property of the response. The default value is `false`.
236
+ * @example
237
+ * ```ts
238
+ * const mailchannels = new MailChannels('your-api-key')
239
+ * const { success, data, error } = await mailchannels.emails.send({
240
+ * to: 'to@example.com',
241
+ * from: 'from@example.com',
242
+ * subject: 'Test',
243
+ * html: 'Test'
244
+ * })
245
+ * ```
246
+ */
247
+ async send(options, dryRun = false) {
248
+ return this._sendEmail(options, { dryRun });
249
+ }
250
+ /**
251
+ * Queues an email message for asynchronous processing and returns immediately with a request ID.
252
+ *
253
+ * The email will be processed in the background, and you'll receive webhook events for all delivery status updates (e.g. `dropped`, `processed`, `delivered`, `hard-bounced`). These webhook events are identical to those sent for the synchronous /send endpoint.
254
+ *
255
+ * Use this endpoint when you need to send emails without waiting for processing to complete. This can improve your application's response time, especially when sending to multiple recipients.
256
+ * @param options - The email options to send.
257
+ * @example
258
+ * ```ts
259
+ * const mailchannels = new MailChannels('your-api-key')
260
+ * const { data, error } = await mailchannels.emails.sendAsync({
261
+ * to: 'to@example.com',
262
+ * from: 'from@example.com',
263
+ * subject: 'Test',
264
+ * html: 'Test'
265
+ * })
266
+ * ```
267
+ */
268
+ async sendAsync(options) {
269
+ return this._sendEmail(options, { async: true });
235
270
  }
236
271
  /**
237
272
  * Validates a domain's email authentication setup by retrieving its DKIM, SPF, and Domain Lockdown status. This endpoint checks whether the domain is properly configured for secure email delivery.
@@ -239,7 +274,7 @@ class Emails {
239
274
  * @example
240
275
  * ```ts
241
276
  * const mailchannels = new MailChannels('your-api-key')
242
- * const { results } = await mailchannels.emails.checkDomain({
277
+ * const { data, error } = await mailchannels.emails.checkDomain({
243
278
  * dkim: [{
244
279
  * domain: 'example.com',
245
280
  * privateKey: 'your-private-key',
@@ -251,9 +286,9 @@ class Emails {
251
286
  * ```
252
287
  */
253
288
  async checkDomain(options) {
289
+ let error = null;
254
290
  const { dkim, domain, senderId } = options;
255
291
  const dkimOptions = dkim ? Array.isArray(dkim) ? dkim : [dkim] : void 0;
256
- const result = { data: null, error: null };
257
292
  const payload = {
258
293
  dkim_settings: dkimOptions?.map(({ domain: domain2, privateKey, selector }) => ({
259
294
  dkim_domain: domain2,
@@ -266,17 +301,17 @@ class Emails {
266
301
  const response = await this.mailchannels.post("/tx/v1/check-domain", {
267
302
  body: payload,
268
303
  onResponseError: async ({ response: response2 }) => {
269
- result.error = getStatusError(response2, {
304
+ error = getStatusError(response2, {
270
305
  [ErrorCode.BadRequest]: "Bad Request.",
271
306
  [ErrorCode.Forbidden]: "User does not have access to this feature."
272
307
  });
273
308
  }
274
- }).catch((error) => {
275
- result.error = getResultError(result, error, "Failed to check domain.");
309
+ }).catch((e) => {
310
+ error ||= getResultError(e, "Failed to check domain.");
276
311
  return null;
277
312
  });
278
- if (!response) return result;
279
- result.data = clean({
313
+ if (!response) return { data: null, error };
314
+ const data = clean({
280
315
  dkim: response.check_results.dkim.map((dkimResults) => ({
281
316
  domain: dkimResults.dkim_domain,
282
317
  keyStatus: dkimResults.dkim_key_status,
@@ -289,7 +324,7 @@ class Emails {
289
324
  spf: response.check_results.spf,
290
325
  references: response.references
291
326
  });
292
- return result;
327
+ return { data, error: null };
293
328
  }
294
329
  /**
295
330
  * Create a DKIM key pair for a specified domain and selector using the specified algorithm and key length, for the current customer.
@@ -304,11 +339,11 @@ class Emails {
304
339
  * ```
305
340
  */
306
341
  async createDkimKey(domain, options) {
307
- const result = { data: null, error: null };
342
+ let error = null;
308
343
  if (!options.selector || options.selector.length > 63) {
309
- result.error = "Selector must be between 1 and 63 characters.";
344
+ error = createError("Selector must be between 1 and 63 characters.");
345
+ return { data: null, error };
310
346
  }
311
- if (result.error) return result;
312
347
  const payload = {
313
348
  algorithm: options.algorithm,
314
349
  key_length: options.length,
@@ -317,17 +352,17 @@ class Emails {
317
352
  const response = await this.mailchannels.post(`/tx/v1/domains/${domain}/dkim-keys`, {
318
353
  body: payload,
319
354
  onResponseError: async ({ response: response2 }) => {
320
- result.error = getStatusError(response2, {
355
+ error = getStatusError(response2, {
321
356
  [ErrorCode.BadRequest]: "Bad Request.",
322
357
  [ErrorCode.Conflict]: "Key pair already created for domain, and selector."
323
358
  });
324
359
  }
325
- }).catch((error) => {
326
- result.error = getResultError(result, error, "Failed to create DKIM key.");
360
+ }).catch((e) => {
361
+ error ||= getResultError(e, "Failed to create DKIM key.");
327
362
  return null;
328
363
  });
329
- if (!response) return result;
330
- result.data = clean({
364
+ if (!response) return { data: null, error };
365
+ const data = clean({
331
366
  algorithm: response.algorithm,
332
367
  createdAt: response.created_at,
333
368
  dnsRecords: response.dkim_dns_records,
@@ -340,7 +375,7 @@ class Emails {
340
375
  status: response.status,
341
376
  statusModifiedAt: response.status_modified_at
342
377
  });
343
- return result;
378
+ return { data, error: null };
344
379
  }
345
380
  /**
346
381
  * Search for DKIM keys by domain, with optional filters. If selector is provided, at most one key will be returned.
@@ -355,13 +390,13 @@ class Emails {
355
390
  * ```
356
391
  */
357
392
  async getDkimKeys(domain, options) {
358
- const result = { data: null, error: null };
393
+ let error = null;
359
394
  if (options?.selector && options.selector.length > 63) {
360
- result.error = "Selector must be between 1 and 63 characters.";
361
- return result;
395
+ error = createError("Selector must be between 1 and 63 characters.");
396
+ return { data: null, error };
362
397
  }
363
- result.error = validateLimit(options?.limit, 100) || validateOffset(options?.offset);
364
- if (result.error) return result;
398
+ error = validateLimit(options?.limit, 100) || validateOffset(options?.offset);
399
+ if (error) return { data: null, error };
365
400
  const payload = {
366
401
  selector: options?.selector,
367
402
  status: options?.status,
@@ -372,16 +407,16 @@ class Emails {
372
407
  const response = await this.mailchannels.get(`/tx/v1/domains/${domain}/dkim-keys`, {
373
408
  query: payload,
374
409
  onResponseError: async ({ response: response2 }) => {
375
- result.error = getStatusError(response2, {
410
+ error = getStatusError(response2, {
376
411
  [ErrorCode.BadRequest]: "Bad Request."
377
412
  });
378
413
  }
379
- }).catch((error) => {
380
- result.error = getResultError(result, error, "Failed to fetch DKIM keys.");
414
+ }).catch((e) => {
415
+ error ||= getResultError(e, "Failed to fetch DKIM keys.");
381
416
  return null;
382
417
  });
383
- if (!response) return result;
384
- result.data = clean(response.keys.map((key) => ({
418
+ if (!response) return { data: null, error };
419
+ const data = clean(response.keys.map((key) => ({
385
420
  algorithm: key.algorithm,
386
421
  createdAt: key.created_at,
387
422
  dnsRecords: key.dkim_dns_records,
@@ -394,7 +429,7 @@ class Emails {
394
429
  status: key.status,
395
430
  statusModifiedAt: key.status_modified_at
396
431
  })));
397
- return result;
432
+ return { data, error: null };
398
433
  }
399
434
  /**
400
435
  * Update fields of an existing DKIM key pair for the specified domain and selector, for the current customer. Currently, only the `status` field can be updated.
@@ -409,31 +444,26 @@ class Emails {
409
444
  * })
410
445
  */
411
446
  async updateDkimKey(domain, options) {
412
- const result = { success: false, error: null };
447
+ let error = null;
413
448
  if (!options.selector || options.selector.length > 63) {
414
- result.error = "Selector must be between 1 and 63 characters.";
415
- return result;
449
+ error = createError("Selector must be between 1 and 63 characters.");
450
+ return { success: false, error };
416
451
  }
417
452
  const payload = {
418
453
  status: options.status
419
454
  };
420
455
  await this.mailchannels.patch(`/tx/v1/domains/${domain}/dkim-keys/${options.selector}`, {
421
456
  body: payload,
422
- ignoreResponseError: true,
423
- onResponse: async ({ response }) => {
424
- if (response.ok) {
425
- result.success = true;
426
- return;
427
- }
428
- result.error = getStatusError(response, {
457
+ onResponseError: async ({ response }) => {
458
+ error = getStatusError(response, {
429
459
  [ErrorCode.BadRequest]: "Bad Request.",
430
460
  [ErrorCode.NotFound]: "Specified key pair not found, or no active key for rotation. This may also occur if the DKIM domain or selector path parameter is missing."
431
461
  });
432
462
  }
433
- }).catch((error) => {
434
- result.error = getResultError(result, error, "Failed to update DKIM key.");
463
+ }).catch((e) => {
464
+ error ||= getResultError(e, "Failed to update DKIM key.");
435
465
  });
436
- return result;
466
+ return { success: !error, error };
437
467
  }
438
468
  /**
439
469
  * Rotate an active DKIM key pair. Mark the original key as `rotated`, and create a new key pair with the required new key selector, reusing the same algorithm and key length. The rotated key remains valid for signing for a 3-day grace period, and is automatically changed to `retired` 2 weeks after rotation. Publish the new key to its DNS TXT record before rotated key expires for signing as emails sent with an unpublished key will fail DKIM validation by receiving providers. After the grace period, only the new key is valid for signing if published.
@@ -452,14 +482,14 @@ class Emails {
452
482
  * ```
453
483
  */
454
484
  async rotateDkimKey(domain, selector, options) {
455
- const result = { data: null, error: null };
485
+ let error = null;
456
486
  if (!selector || selector.length > 63) {
457
- result.error = "Selector must be between 1 and 63 characters.";
458
- return result;
487
+ error = createError("Selector must be between 1 and 63 characters.");
488
+ return { data: null, error };
459
489
  }
460
490
  if (!options.newKey.selector || options.newKey.selector.length > 63) {
461
- result.error = "New key selector must be between 1 and 63 characters.";
462
- return result;
491
+ error = createError("New key selector must be between 1 and 63 characters.");
492
+ return { data: null, error };
463
493
  }
464
494
  const payload = {
465
495
  new_key: {
@@ -469,18 +499,18 @@ class Emails {
469
499
  const response = await this.mailchannels.post(`/tx/v1/domains/${domain}/dkim-keys/${selector}/rotate`, {
470
500
  body: payload,
471
501
  onResponseError: async ({ response: response2 }) => {
472
- result.error = getStatusError(response2, {
502
+ error = getStatusError(response2, {
473
503
  [ErrorCode.BadRequest]: "Bad Request.",
474
504
  [ErrorCode.NotFound]: "Specified key pair not found.",
475
505
  [ErrorCode.Conflict]: "Key pair already created for domain, and provided new key selector."
476
506
  });
477
507
  }
478
- }).catch((error) => {
479
- result.error = getResultError(result, error, "Failed to rotate DKIM key.");
508
+ }).catch((e) => {
509
+ error ||= getResultError(e, "Failed to rotate DKIM key.");
480
510
  return null;
481
511
  });
482
- if (!response) return result;
483
- result.data = clean({
512
+ if (!response) return { data: null, error };
513
+ const data = clean({
484
514
  new: {
485
515
  algorithm: response.new_key.algorithm,
486
516
  createdAt: response.new_key.created_at,
@@ -508,7 +538,7 @@ class Emails {
508
538
  statusModifiedAt: response.rotated_key.status_modified_at
509
539
  }
510
540
  });
511
- return result;
541
+ return { data, error: null };
512
542
  }
513
543
  }
514
544
 
@@ -526,33 +556,28 @@ class Webhooks {
526
556
  * ```
527
557
  */
528
558
  async enroll(endpoint) {
529
- const result = { success: false, error: null };
559
+ let error = null;
530
560
  if (!endpoint) {
531
- result.error = "No endpoint provided.";
532
- return result;
561
+ error = createError("No endpoint provided.");
562
+ return { success: false, error };
533
563
  }
534
564
  if (endpoint.length > 8e3) {
535
- result.error = "The endpoint exceeds the maximum length of 8000 characters.";
536
- return result;
565
+ error = createError("The endpoint exceeds the maximum length of 8000 characters.");
566
+ return { success: false, error };
537
567
  }
538
568
  await this.mailchannels.post("/tx/v1/webhook", {
539
569
  query: {
540
570
  endpoint
541
571
  },
542
- ignoreResponseError: true,
543
- onResponse: async ({ response }) => {
544
- if (response.ok) {
545
- result.success = true;
546
- return;
547
- }
548
- result.error = getStatusError(response, {
572
+ onResponseError: async ({ response }) => {
573
+ error = getStatusError(response, {
549
574
  [ErrorCode.Conflict]: `Endpoint '${endpoint}' is already enrolled to receive notifications.`
550
575
  });
551
576
  }
552
- }).catch((error) => {
553
- result.error = getResultError(result, error, "Failed to enroll webhook.");
577
+ }).catch((e) => {
578
+ error ||= getResultError(e, "Failed to enroll webhook.");
554
579
  });
555
- return result;
580
+ return { success: !error, error };
556
581
  }
557
582
  /**
558
583
  * Retrieves all registered webhook endpoints associated with the customer.
@@ -563,18 +588,18 @@ class Webhooks {
563
588
  * ```
564
589
  */
565
590
  async list() {
566
- const result = { data: null, error: null };
591
+ let error = null;
567
592
  const response = await this.mailchannels.get("/tx/v1/webhook", {
568
593
  onResponseError: async ({ response: response2 }) => {
569
- result.error = getStatusError(response2);
594
+ error = getStatusError(response2);
570
595
  }
571
- }).catch((error) => {
572
- result.error = getResultError(result, error, "Failed to fetch webhooks.");
596
+ }).catch((e) => {
597
+ error ||= getResultError(e, "Failed to fetch webhooks.");
573
598
  return null;
574
599
  });
575
- if (!response) return result;
576
- result.data = clean(response.map(({ webhook }) => webhook));
577
- return result;
600
+ if (!response) return { data: null, error };
601
+ const data = clean(response.map(({ webhook }) => webhook));
602
+ return { data, error: null };
578
603
  }
579
604
  /**
580
605
  * Deletes all registered webhook endpoints for the customer.
@@ -585,20 +610,15 @@ class Webhooks {
585
610
  * ```
586
611
  */
587
612
  async delete() {
588
- const result = { success: false, error: null };
613
+ let error = null;
589
614
  await this.mailchannels.delete("/tx/v1/webhook", {
590
- ignoreResponseError: true,
591
- onResponse: async ({ response }) => {
592
- if (!response.ok) {
593
- result.error = getStatusError(response);
594
- return;
595
- }
596
- result.success = true;
615
+ onResponseError: async ({ response }) => {
616
+ error = getStatusError(response);
597
617
  }
598
- }).catch((error) => {
599
- result.error = getResultError(result, error, "Failed to delete webhooks.");
618
+ }).catch((e) => {
619
+ error ||= getResultError(e, "Failed to delete webhooks.");
600
620
  });
601
- return result;
621
+ return { success: !error, error };
602
622
  }
603
623
  /**
604
624
  * Retrieves the public key used to verify signatures on incoming webhook payloads.
@@ -610,24 +630,24 @@ class Webhooks {
610
630
  * ```
611
631
  */
612
632
  async getSigningKey(id) {
613
- const result = { data: null, error: null };
633
+ let error = null;
614
634
  const response = await this.mailchannels.get("/tx/v1/webhook/public-key", {
615
635
  query: {
616
636
  id
617
637
  },
618
638
  onResponseError: async ({ response: response2 }) => {
619
- result.error = getStatusError(response2, {
639
+ error = getStatusError(response2, {
620
640
  [ErrorCode.BadRequest]: "Bad Request.",
621
641
  [ErrorCode.NotFound]: `The key '${id}' is not found.`
622
642
  });
623
643
  }
624
- }).catch((error) => {
625
- result.error = getResultError(result, error, "Failed to get signing key.");
644
+ }).catch((e) => {
645
+ error ||= getResultError(e, "Failed to get signing key.");
626
646
  return null;
627
647
  });
628
- if (!response) return result;
629
- result.data = clean({ key: response.key });
630
- return result;
648
+ if (!response) return { data: null, error };
649
+ const data = clean({ key: response.key });
650
+ return { data, error: null };
631
651
  }
632
652
  /**
633
653
  * Validates whether your enrolled webhook(s) respond with an HTTP `2xx` status code. Sends a test request to each webhook containing your customer handle, a hardcoded event type (`test`), a hardcoded sender email (`test@mailchannels.com`), a timestamp, a request ID (provided or generated), and an SMTP ID. The response includes the HTTP status code and body returned by each webhook.
@@ -639,31 +659,31 @@ class Webhooks {
639
659
  * ```
640
660
  */
641
661
  async validate(requestId) {
642
- const result = { data: null, error: null };
662
+ let error = null;
643
663
  if (requestId && requestId.length > 28) {
644
- result.error = "The request id should not exceed 28 characters.";
645
- return result;
664
+ error = createError("The request id should not exceed 28 characters.");
665
+ return { data: null, error };
646
666
  }
647
667
  const response = await this.mailchannels.post("/tx/v1/webhook/validate", {
648
668
  body: {
649
669
  request_id: requestId
650
670
  },
651
671
  onResponseError: async ({ response: response2 }) => {
652
- result.error = getStatusError(response2, {
672
+ error = getStatusError(response2, {
653
673
  [ErrorCode.BadRequest]: "Bad Request.",
654
674
  [ErrorCode.NotFound]: "No webhooks found for the account."
655
675
  });
656
676
  }
657
- }).catch((error) => {
658
- result.error = getResultError(result, error, "Failed to validate webhooks.");
677
+ }).catch((e) => {
678
+ error ||= getResultError(e, "Failed to validate webhooks.");
659
679
  return null;
660
680
  });
661
- if (!response) return result;
662
- result.data = clean({
681
+ if (!response) return { data: null, error };
682
+ const data = clean({
663
683
  allPassed: response.all_passed,
664
684
  results: response.results
665
685
  });
666
- return result;
686
+ return { data, error: null };
667
687
  }
668
688
  }
669
689
 
@@ -684,17 +704,17 @@ class SubAccounts {
684
704
  * ```
685
705
  */
686
706
  async create(companyName, handle) {
687
- const result = { data: null, error: null };
707
+ let error = null;
688
708
  const isValidCompany = SubAccounts.COMPANY_PATTERN.test(companyName);
689
709
  if (!isValidCompany) {
690
- result.error = "Invalid company name. Company name must be between 3 and 128 characters.";
691
- return result;
710
+ error = createError("Invalid company name. Company name must be between 3 and 128 characters.");
711
+ return { data: null, error };
692
712
  }
693
713
  if (handle) {
694
714
  const isValidHandle = SubAccounts.HANDLE_PATTERN.test(handle);
695
715
  if (!isValidHandle) {
696
- result.error = "Invalid handle. Sub-account handle must be between 3 and 128 characters and contain only lowercase letters and numbers.";
697
- return result;
716
+ error = createError("Invalid handle. Sub-account handle must be between 3 and 128 characters and contain only lowercase letters and numbers.");
717
+ return { data: null, error };
698
718
  }
699
719
  }
700
720
  const response = await this.mailchannels.post("/tx/v1/sub-account", {
@@ -703,22 +723,22 @@ class SubAccounts {
703
723
  handle
704
724
  },
705
725
  onResponseError: async ({ response: response2 }) => {
706
- result.error = getStatusError(response2, {
726
+ error = getStatusError(response2, {
707
727
  [ErrorCode.Forbidden]: "The parent account does not have permission to create sub-accounts.",
708
728
  [ErrorCode.Conflict]: `Sub-account with handle '${handle}' already exists.`
709
729
  });
710
730
  }
711
- }).catch((error) => {
712
- result.error = getResultError(result, error, "Failed to create sub-account.");
731
+ }).catch((e) => {
732
+ error ||= getResultError(e, "Failed to create sub-account.");
713
733
  return null;
714
734
  });
715
- if (!response) return result;
716
- result.data = clean({
735
+ if (!response) return { data: null, error };
736
+ const data = clean({
717
737
  companyName: response.company_name,
718
738
  enabled: response.enabled,
719
739
  handle: response.handle
720
740
  });
721
- return result;
741
+ return { data, error: null };
722
742
  }
723
743
  /**
724
744
  * Retrieves all sub-accounts associated with the parent account. The response is paginated with a default limit of 1000 sub-accounts per page and an offset of 0.
@@ -730,25 +750,25 @@ class SubAccounts {
730
750
  * ```
731
751
  */
732
752
  async list(options) {
733
- const result = { data: null, error: null };
734
- result.error = validateLimit(options?.limit, 1e3) || validateOffset(options?.offset);
735
- if (result.error) return result;
753
+ let error = null;
754
+ error = validateLimit(options?.limit, 1e3) || validateOffset(options?.offset);
755
+ if (error) return { data: null, error };
736
756
  const response = await this.mailchannels.get("/tx/v1/sub-account", {
737
757
  query: options,
738
758
  onResponseError: async ({ response: response2 }) => {
739
- result.error = getStatusError(response2);
759
+ error = getStatusError(response2);
740
760
  }
741
- }).catch((error) => {
742
- result.error = getResultError(result, error, "Failed to fetch sub-accounts.");
761
+ }).catch((e) => {
762
+ error ||= getResultError(e, "Failed to fetch sub-accounts.");
743
763
  return null;
744
764
  });
745
- if (!response) return result;
746
- result.data = clean(response.map((account) => ({
765
+ if (!response) return { data: null, error };
766
+ const data = clean(response.map((account) => ({
747
767
  companyName: account.company_name,
748
768
  enabled: account.enabled,
749
769
  handle: account.handle
750
770
  })));
751
- return result;
771
+ return { data, error: null };
752
772
  }
753
773
  /**
754
774
  * Deletes the sub-account identified by its handle.
@@ -759,24 +779,19 @@ class SubAccounts {
759
779
  * ```
760
780
  */
761
781
  async delete(handle) {
762
- const result = { success: false, error: null };
782
+ let error = null;
763
783
  if (!handle) {
764
- result.error = "No handle provided.";
765
- return result;
784
+ error = createError("No handle provided.");
785
+ return { success: false, error };
766
786
  }
767
787
  await this.mailchannels.delete(`/tx/v1/sub-account/${handle}`, {
768
- ignoreResponseError: true,
769
- onResponse: async ({ response }) => {
770
- if (!response.ok) {
771
- result.error = getStatusError(response);
772
- return;
773
- }
774
- result.success = true;
788
+ onResponseError: async ({ response }) => {
789
+ error = getStatusError(response);
775
790
  }
776
- }).catch((error) => {
777
- result.error = getResultError(result, error, "Failed to delete sub-account.");
791
+ }).catch((e) => {
792
+ error ||= getResultError(e, "Failed to delete sub-account.");
778
793
  });
779
- return result;
794
+ return { success: !error, error };
780
795
  }
781
796
  /**
782
797
  * Suspends the sub-account identified by its handle. This action disables the account, preventing it from sending any emails until it is reactivated.
@@ -788,26 +803,21 @@ class SubAccounts {
788
803
  * ```
789
804
  */
790
805
  async suspend(handle) {
791
- const result = { success: false, error: null };
806
+ let error = null;
792
807
  if (!handle) {
793
- result.error = "No handle provided.";
794
- return result;
808
+ error = createError("No handle provided.");
809
+ return { success: false, error };
795
810
  }
796
811
  await this.mailchannels.post(`/tx/v1/sub-account/${handle}/suspend`, {
797
- ignoreResponseError: true,
798
- onResponse: async ({ response }) => {
799
- if (response.ok) {
800
- result.success = true;
801
- return;
802
- }
803
- result.error = getStatusError(response, {
812
+ onResponseError: async ({ response }) => {
813
+ error = getStatusError(response, {
804
814
  [ErrorCode.NotFound]: `The specified sub-account '${handle}' does not exist.`
805
815
  });
806
816
  }
807
- }).catch((error) => {
808
- result.error = getResultError(result, error, "Failed to suspend sub-account.");
817
+ }).catch((e) => {
818
+ error ||= getResultError(e, "Failed to suspend sub-account.");
809
819
  });
810
- return result;
820
+ return { success: !error, error };
811
821
  }
812
822
  /**
813
823
  * Activates a suspended sub-account identified by its handle, restoring its ability to send emails.
@@ -819,27 +829,22 @@ class SubAccounts {
819
829
  * ```
820
830
  */
821
831
  async activate(handle) {
822
- const result = { success: false, error: null };
832
+ let error = null;
823
833
  if (!handle) {
824
- result.error = "No handle provided.";
825
- return result;
834
+ error = createError("No handle provided.");
835
+ return { success: false, error };
826
836
  }
827
837
  await this.mailchannels.post(`/tx/v1/sub-account/${handle}/activate`, {
828
- ignoreResponseError: true,
829
- onResponse: async ({ response }) => {
830
- if (response.ok) {
831
- result.success = true;
832
- return;
833
- }
834
- result.error = getStatusError(response, {
838
+ onResponseError: async ({ response }) => {
839
+ error = getStatusError(response, {
835
840
  [ErrorCode.Forbidden]: "The parent account does not have permission to activate the sub-account.",
836
841
  [ErrorCode.NotFound]: `The specified sub-account '${handle}' does not exist.`
837
842
  });
838
843
  }
839
- }).catch((error) => {
840
- result.error = getResultError(result, error, "Failed to activate sub-account.");
844
+ }).catch((e) => {
845
+ error ||= getResultError(e, "Failed to activate sub-account.");
841
846
  });
842
- return result;
847
+ return { success: !error, error };
843
848
  }
844
849
  /**
845
850
  * Creates a new API key for the specified sub-account.
@@ -851,29 +856,29 @@ class SubAccounts {
851
856
  * ```
852
857
  */
853
858
  async createApiKey(handle) {
854
- const result = { data: null, error: null };
859
+ let error = null;
855
860
  if (!handle) {
856
- result.error = "No handle provided.";
857
- return result;
861
+ error = createError("No handle provided.");
862
+ return { data: null, error };
858
863
  }
859
864
  const response = await this.mailchannels.post(`/tx/v1/sub-account/${handle}/api-key`, {
860
865
  onResponseError: async ({ response: response2 }) => {
861
- result.error = getStatusError(response2, {
866
+ error = getStatusError(response2, {
862
867
  [ErrorCode.Forbidden]: "You can't create API keys for this sub-account.",
863
868
  [ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`,
864
869
  [ErrorCode.UnprocessableEntity]: "You have reached the limit of API keys you can create for this sub-account."
865
870
  });
866
871
  }
867
- }).catch((error) => {
868
- result.error = getResultError(result, error, "Failed to create sub-account API key.");
872
+ }).catch((e) => {
873
+ error ||= getResultError(e, "Failed to create sub-account API key.");
869
874
  return null;
870
875
  });
871
- if (!response) return result;
872
- result.data = clean({
876
+ if (!response) return { data: null, error };
877
+ const data = clean({
873
878
  id: response.id,
874
879
  value: response.key
875
880
  });
876
- return result;
881
+ return { data, error: null };
877
882
  }
878
883
  /**
879
884
  * Retrieves details of all API keys associated with the specified sub-account. For security reasons, the full API key is not returned; only the key ID and a partially redacted version are provided.
@@ -886,29 +891,29 @@ class SubAccounts {
886
891
  * ```
887
892
  */
888
893
  async listApiKeys(handle, options) {
889
- const result = { data: null, error: null };
894
+ let error = null;
890
895
  if (!handle) {
891
- result.error = "No handle provided.";
892
- return result;
896
+ error = createError("No handle provided.");
897
+ return { data: null, error };
893
898
  }
894
- result.error = validateLimit(options?.limit, 1e3) || validateOffset(options?.offset);
895
- if (result.error) return result;
899
+ error = validateLimit(options?.limit, 1e3) || validateOffset(options?.offset);
900
+ if (error) return { data: null, error };
896
901
  const response = await this.mailchannels.get(`/tx/v1/sub-account/${handle}/api-key`, {
897
902
  onResponseError: async ({ response: response2 }) => {
898
- result.error = getStatusError(response2, {
903
+ error = getStatusError(response2, {
899
904
  [ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`
900
905
  });
901
906
  }
902
- }).catch((error) => {
903
- result.error = getResultError(result, error, "Failed to fetch sub-account API keys.");
907
+ }).catch((e) => {
908
+ error ||= getResultError(e, "Failed to fetch sub-account API keys.");
904
909
  return null;
905
910
  });
906
- if (!response) return result;
907
- result.data = clean(response.map((key) => ({
911
+ if (!response) return { data: null, error };
912
+ const data = clean(response.map((key) => ({
908
913
  id: key.id,
909
914
  value: key.key
910
915
  })));
911
- return result;
916
+ return { data, error: null };
912
917
  }
913
918
  /**
914
919
  * Deletes the API key identified by its ID for the specified sub-account.
@@ -921,26 +926,21 @@ class SubAccounts {
921
926
  * ```
922
927
  */
923
928
  async deleteApiKey(handle, id) {
924
- const result = { success: false, error: null };
929
+ let error = null;
925
930
  if (!handle) {
926
- result.error = "No handle provided.";
927
- return result;
931
+ error = createError("No handle provided.");
932
+ return { success: false, error };
928
933
  }
929
934
  await this.mailchannels.delete(`/tx/v1/sub-account/${handle}/api-key/${id}`, {
930
- ignoreResponseError: true,
931
- onResponse: async ({ response }) => {
932
- if (response.ok) {
933
- result.success = true;
934
- return;
935
- }
936
- result.error = getStatusError(response, {
935
+ onResponseError: async ({ response }) => {
936
+ error = getStatusError(response, {
937
937
  [ErrorCode.BadRequest]: "Missing or invalid API key ID."
938
938
  });
939
939
  }
940
- }).catch((error) => {
941
- result.error = getResultError(result, error, "Failed to delete sub-account API key.");
940
+ }).catch((e) => {
941
+ error ||= getResultError(e, "Failed to delete sub-account API key.");
942
942
  });
943
- return result;
943
+ return { success: !error, error };
944
944
  }
945
945
  /**
946
946
  * Creates a new SMTP password for the specified sub-account.
@@ -952,30 +952,30 @@ class SubAccounts {
952
952
  * ```
953
953
  */
954
954
  async createSmtpPassword(handle) {
955
- const result = { data: null, error: null };
955
+ let error = null;
956
956
  if (!handle) {
957
- result.error = "No handle provided.";
958
- return result;
957
+ error = createError("No handle provided.");
958
+ return { data: null, error };
959
959
  }
960
960
  const response = await this.mailchannels.post(`/tx/v1/sub-account/${handle}/smtp-password`, {
961
961
  onResponseError: async ({ response: response2 }) => {
962
- result.error = getStatusError(response2, {
962
+ error = getStatusError(response2, {
963
963
  [ErrorCode.Forbidden]: "You can't create SMTP passwords for this sub-account.",
964
964
  [ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`,
965
965
  [ErrorCode.UnprocessableEntity]: "You have reached the limit of SMTP passwords you can create for this sub-account."
966
966
  });
967
967
  }
968
- }).catch((error) => {
969
- result.error = getResultError(result, error, "Failed to create sub-account SMTP password.");
968
+ }).catch((e) => {
969
+ error ||= getResultError(e, "Failed to create sub-account SMTP password.");
970
970
  return null;
971
971
  });
972
- if (!response) return result;
973
- result.data = clean({
972
+ if (!response) return { data: null, error };
973
+ const data = clean({
974
974
  enabled: response.enabled,
975
975
  id: response.id,
976
976
  value: response.smtp_password
977
977
  });
978
- return result;
978
+ return { data, error: null };
979
979
  }
980
980
  /**
981
981
  * Retrieves details of all SMTP passwords associated with the specified sub-account. For security, the full SMTP password is not returned; only the password ID and a partially redacted version are provided.
@@ -987,28 +987,28 @@ class SubAccounts {
987
987
  * ```
988
988
  */
989
989
  async listSmtpPasswords(handle) {
990
- const result = { data: null, error: null };
990
+ let error = null;
991
991
  if (!handle) {
992
- result.error = "No handle provided.";
993
- return result;
992
+ error = createError("No handle provided.");
993
+ return { data: null, error };
994
994
  }
995
995
  const response = await this.mailchannels.get(`/tx/v1/sub-account/${handle}/smtp-password`, {
996
996
  onResponseError: async ({ response: response2 }) => {
997
- result.error = getStatusError(response2, {
997
+ error = getStatusError(response2, {
998
998
  [ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`
999
999
  });
1000
1000
  }
1001
- }).catch((error) => {
1002
- result.error = getResultError(result, error, "Failed to fetch sub-account SMTP passwords.");
1001
+ }).catch((e) => {
1002
+ error ||= getResultError(e, "Failed to fetch sub-account SMTP passwords.");
1003
1003
  return null;
1004
1004
  });
1005
- if (!response) return result;
1006
- result.data = clean(response.map((password) => ({
1005
+ if (!response) return { data: null, error };
1006
+ const data = clean(response.map((password) => ({
1007
1007
  enabled: password.enabled,
1008
1008
  id: password.id,
1009
1009
  value: password.smtp_password
1010
1010
  })));
1011
- return result;
1011
+ return { data, error: null };
1012
1012
  }
1013
1013
  /**
1014
1014
  * Deletes the SMTP password identified by its ID for the specified sub-account.
@@ -1021,26 +1021,21 @@ class SubAccounts {
1021
1021
  * ```
1022
1022
  */
1023
1023
  async deleteSmtpPassword(handle, id) {
1024
- const result = { success: false, error: null };
1024
+ let error = null;
1025
1025
  if (!handle) {
1026
- result.error = "No handle provided.";
1027
- return result;
1026
+ error = createError("No handle provided.");
1027
+ return { success: false, error };
1028
1028
  }
1029
1029
  await this.mailchannels.delete(`/tx/v1/sub-account/${handle}/smtp-password/${id}`, {
1030
- ignoreResponseError: true,
1031
- onResponse: async ({ response }) => {
1032
- if (response.ok) {
1033
- result.success = true;
1034
- return;
1035
- }
1036
- result.error = getStatusError(response, {
1030
+ onResponseError: async ({ response }) => {
1031
+ error = getStatusError(response, {
1037
1032
  [ErrorCode.BadRequest]: "Missing or invalid SMTP password ID."
1038
1033
  });
1039
1034
  }
1040
- }).catch((error) => {
1041
- result.error = getResultError(result, error, "Failed to delete sub-account SMTP password.");
1035
+ }).catch((e) => {
1036
+ error ||= getResultError(e, "Failed to delete sub-account SMTP password.");
1042
1037
  });
1043
- return result;
1038
+ return { success: !error, error };
1044
1039
  }
1045
1040
  /**
1046
1041
  * Retrieves the limit of a specified sub-account. A value of `-1` indicates that the sub-account inherits the parent account's limit, allowing the sub-account to utilize any remaining capacity within the parent account's allocation.
@@ -1052,24 +1047,24 @@ class SubAccounts {
1052
1047
  * ```
1053
1048
  */
1054
1049
  async getLimit(handle) {
1055
- const result = { data: null, error: null };
1050
+ let error = null;
1056
1051
  if (!handle) {
1057
- result.error = "No handle provided.";
1058
- return result;
1052
+ error = createError("No handle provided.");
1053
+ return { data: null, error };
1059
1054
  }
1060
1055
  const response = await this.mailchannels.get(`/tx/v1/sub-account/${handle}/limit`, {
1061
1056
  onResponseError: async ({ response: response2 }) => {
1062
- result.error = getStatusError(response2, {
1057
+ error = getStatusError(response2, {
1063
1058
  [ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`
1064
1059
  });
1065
1060
  }
1066
- }).catch((error) => {
1067
- result.error = getResultError(result, error, "Failed to fetch sub-account limit.");
1061
+ }).catch((e) => {
1062
+ error ||= getResultError(e, "Failed to fetch sub-account limit.");
1068
1063
  return null;
1069
1064
  });
1070
- if (!response) return result;
1071
- result.data = clean(response);
1072
- return result;
1065
+ if (!response) return { data: null, error };
1066
+ const data = clean(response);
1067
+ return { data, error: null };
1073
1068
  }
1074
1069
  /**
1075
1070
  * Sets the limit for the specified sub-account.
@@ -1082,28 +1077,23 @@ class SubAccounts {
1082
1077
  * ```
1083
1078
  */
1084
1079
  async setLimit(handle, limit) {
1085
- const result = { success: false, error: null };
1080
+ let error = null;
1086
1081
  if (!handle) {
1087
- result.error = "No handle provided.";
1088
- return result;
1082
+ error = createError("No handle provided.");
1083
+ return { success: false, error };
1089
1084
  }
1090
1085
  await this.mailchannels.put(`/tx/v1/sub-account/${handle}/limit`, {
1091
1086
  body: limit,
1092
- ignoreResponseError: true,
1093
- onResponse: async ({ response }) => {
1094
- if (response.ok) {
1095
- result.success = true;
1096
- return;
1097
- }
1098
- result.error = getStatusError(response, {
1087
+ onResponseError: async ({ response }) => {
1088
+ error = getStatusError(response, {
1099
1089
  [ErrorCode.BadRequest]: "Bad Request.",
1100
1090
  [ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`
1101
1091
  });
1102
1092
  }
1103
- }).catch((error) => {
1104
- result.error = getResultError(result, error, "Failed to set sub-account limit.");
1093
+ }).catch((e) => {
1094
+ error ||= getResultError(e, "Failed to set sub-account limit.");
1105
1095
  });
1106
- return result;
1096
+ return { success: !error, error };
1107
1097
  }
1108
1098
  /**
1109
1099
  * Deletes the limit for the specified sub-account. After a successful deletion, the specified sub-account will be limited to the parent account's limit.
@@ -1115,26 +1105,21 @@ class SubAccounts {
1115
1105
  * ```
1116
1106
  */
1117
1107
  async deleteLimit(handle) {
1118
- const result = { success: false, error: null };
1108
+ let error = null;
1119
1109
  if (!handle) {
1120
- result.error = "No handle provided.";
1121
- return result;
1110
+ error = createError("No handle provided.");
1111
+ return { success: false, error };
1122
1112
  }
1123
1113
  await this.mailchannels.delete(`/tx/v1/sub-account/${handle}/limit`, {
1124
- ignoreResponseError: true,
1125
- onResponse: async ({ response }) => {
1126
- if (response.ok) {
1127
- result.success = true;
1128
- return;
1129
- }
1130
- result.error = getStatusError(response, {
1114
+ onResponseError: async ({ response }) => {
1115
+ error = getStatusError(response, {
1131
1116
  [ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`
1132
1117
  });
1133
1118
  }
1134
- }).catch((error) => {
1135
- result.error = getResultError(result, error, "Failed to delete sub-account limit.");
1119
+ }).catch((e) => {
1120
+ error ||= getResultError(e, "Failed to delete sub-account limit.");
1136
1121
  });
1137
- return result;
1122
+ return { success: !error, error };
1138
1123
  }
1139
1124
  /**
1140
1125
  * Retrieves usage statistics for the specified sub-account during the current billing period.
@@ -1146,28 +1131,28 @@ class SubAccounts {
1146
1131
  * ```
1147
1132
  */
1148
1133
  async getUsage(handle) {
1149
- const result = { data: null, error: null };
1134
+ let error = null;
1150
1135
  if (!handle) {
1151
- result.error = "No handle provided.";
1152
- return result;
1136
+ error = createError("No handle provided.");
1137
+ return { data: null, error };
1153
1138
  }
1154
1139
  const response = await this.mailchannels.get(`/tx/v1/sub-account/${handle}/usage`, {
1155
1140
  onResponseError: async ({ response: response2 }) => {
1156
- result.error = getStatusError(response2, {
1141
+ error = getStatusError(response2, {
1157
1142
  [ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`
1158
1143
  });
1159
1144
  }
1160
- }).catch((error) => {
1161
- result.error = getResultError(result, error, "Failed to fetch sub-account usage.");
1145
+ }).catch((e) => {
1146
+ error ||= getResultError(e, "Failed to fetch sub-account usage.");
1162
1147
  return null;
1163
1148
  });
1164
- if (!response) return result;
1165
- result.data = clean({
1149
+ if (!response) return { data: null, error };
1150
+ const data = clean({
1166
1151
  endDate: response.period_end_date,
1167
1152
  startDate: response.period_start_date,
1168
1153
  total: response.total_usage
1169
1154
  });
1170
- return result;
1155
+ return { data, error: null };
1171
1156
  }
1172
1157
  }
1173
1158
 
@@ -1185,7 +1170,7 @@ class Metrics {
1185
1170
  * ```
1186
1171
  */
1187
1172
  async engagement(options) {
1188
- const result = { data: null, error: null };
1173
+ let error = null;
1189
1174
  const response = await this.mailchannels.get("/tx/v1/metrics/engagement", {
1190
1175
  query: {
1191
1176
  start_time: options?.startTime,
@@ -1194,16 +1179,16 @@ class Metrics {
1194
1179
  interval: options?.interval
1195
1180
  },
1196
1181
  onResponseError: async ({ response: response2 }) => {
1197
- result.error = getStatusError(response2, {
1182
+ error = getStatusError(response2, {
1198
1183
  [ErrorCode.BadRequest]: "Bad Request."
1199
1184
  });
1200
1185
  }
1201
- }).catch((error) => {
1202
- result.error = getResultError(result, error, "Failed to fetch engagement metrics.");
1186
+ }).catch((e) => {
1187
+ error ||= getResultError(e, "Failed to fetch engagement metrics.");
1203
1188
  return null;
1204
1189
  });
1205
- if (!response) return result;
1206
- result.data = clean({
1190
+ if (!response) return { data: null, error };
1191
+ const data = clean({
1207
1192
  buckets: {
1208
1193
  click: mapBuckets(response.buckets.click),
1209
1194
  clickTrackingDelivered: mapBuckets(response.buckets.click_tracking_delivered),
@@ -1217,7 +1202,7 @@ class Metrics {
1217
1202
  openTrackingDelivered: response.open_tracking_delivered,
1218
1203
  startTime: response.start_time
1219
1204
  });
1220
- return result;
1205
+ return { data, error: null };
1221
1206
  }
1222
1207
  /**
1223
1208
  * Retrieve performance metrics for messages sent from your account, including counts of processed, delivered, hard-bounced events. Supports optional filters for time range, and campaign ID.
@@ -1229,7 +1214,7 @@ class Metrics {
1229
1214
  * ```
1230
1215
  */
1231
1216
  async performance(options) {
1232
- const result = { data: null, error: null };
1217
+ let error = null;
1233
1218
  const response = await this.mailchannels.get("/tx/v1/metrics/performance", {
1234
1219
  query: {
1235
1220
  start_time: options?.startTime,
@@ -1238,16 +1223,16 @@ class Metrics {
1238
1223
  interval: options?.interval
1239
1224
  },
1240
1225
  onResponseError: async ({ response: response2 }) => {
1241
- result.error = getStatusError(response2, {
1226
+ error = getStatusError(response2, {
1242
1227
  [ErrorCode.BadRequest]: "Bad Request."
1243
1228
  });
1244
1229
  }
1245
- }).catch((error) => {
1246
- result.error = getResultError(result, error, "Failed to fetch performance metrics.");
1230
+ }).catch((e) => {
1231
+ error ||= getResultError(e, "Failed to fetch performance metrics.");
1247
1232
  return null;
1248
1233
  });
1249
- if (!response) return result;
1250
- result.data = clean({
1234
+ if (!response) return { data: null, error };
1235
+ const data = clean({
1251
1236
  bounced: response.bounced,
1252
1237
  buckets: {
1253
1238
  bounced: mapBuckets(response.buckets.bounced),
@@ -1259,7 +1244,7 @@ class Metrics {
1259
1244
  processed: response.processed,
1260
1245
  startTime: response.start_time
1261
1246
  });
1262
- return result;
1247
+ return { data, error: null };
1263
1248
  }
1264
1249
  /**
1265
1250
  * Retrieve recipient behaviour metrics for messages sent from your account, including counts of unsubscribed events. Supports optional filters for time range, and campaign ID.
@@ -1271,7 +1256,7 @@ class Metrics {
1271
1256
  * ```
1272
1257
  */
1273
1258
  async recipientBehaviour(options) {
1274
- const result = { data: null, error: null };
1259
+ let error = null;
1275
1260
  const response = await this.mailchannels.get("/tx/v1/metrics/recipient-behaviour", {
1276
1261
  query: {
1277
1262
  start_time: options?.startTime,
@@ -1280,16 +1265,16 @@ class Metrics {
1280
1265
  interval: options?.interval
1281
1266
  },
1282
1267
  onResponseError: async ({ response: response2 }) => {
1283
- result.error = getStatusError(response2, {
1268
+ error = getStatusError(response2, {
1284
1269
  [ErrorCode.BadRequest]: "Bad Request."
1285
1270
  });
1286
1271
  }
1287
- }).catch((error) => {
1288
- result.error = getResultError(result, error, "Failed to fetch recipient behaviour metrics.");
1272
+ }).catch((e) => {
1273
+ error ||= getResultError(e, "Failed to fetch recipient behaviour metrics.");
1289
1274
  return null;
1290
1275
  });
1291
- if (!response) return result;
1292
- result.data = clean({
1276
+ if (!response) return { data: null, error };
1277
+ const data = clean({
1293
1278
  buckets: {
1294
1279
  unsubscribeDelivered: mapBuckets(response.buckets.unsubscribe_delivered),
1295
1280
  unsubscribed: mapBuckets(response.buckets.unsubscribed)
@@ -1299,7 +1284,7 @@ class Metrics {
1299
1284
  unsubscribeDelivered: response.unsubscribe_delivered,
1300
1285
  unsubscribed: response.unsubscribed
1301
1286
  });
1302
- return result;
1287
+ return { data, error: null };
1303
1288
  }
1304
1289
  /**
1305
1290
  * Retrieve volume metrics for messages sent from your account, including counts of processed, delivered and dropped events. Supports optional filters for time range and campaign ID.
@@ -1311,7 +1296,7 @@ class Metrics {
1311
1296
  * ```
1312
1297
  */
1313
1298
  async volume(options) {
1314
- const result = { data: null, error: null };
1299
+ let error = null;
1315
1300
  const response = await this.mailchannels.get("/tx/v1/metrics/volume", {
1316
1301
  query: {
1317
1302
  start_time: options?.startTime,
@@ -1320,16 +1305,16 @@ class Metrics {
1320
1305
  interval: options?.interval
1321
1306
  },
1322
1307
  onResponseError: async ({ response: response2 }) => {
1323
- result.error = getStatusError(response2, {
1308
+ error = getStatusError(response2, {
1324
1309
  [ErrorCode.BadRequest]: "Bad Request."
1325
1310
  });
1326
1311
  }
1327
- }).catch((error) => {
1328
- result.error = getResultError(result, error, "Failed to fetch volume metrics.");
1312
+ }).catch((e) => {
1313
+ error ||= getResultError(e, "Failed to fetch volume metrics.");
1329
1314
  return null;
1330
1315
  });
1331
- if (!response) return result;
1332
- result.data = clean({
1316
+ if (!response) return { data: null, error };
1317
+ const data = clean({
1333
1318
  buckets: {
1334
1319
  delivered: mapBuckets(response.buckets.delivered),
1335
1320
  dropped: mapBuckets(response.buckets.dropped),
@@ -1341,7 +1326,7 @@ class Metrics {
1341
1326
  processed: response.processed,
1342
1327
  startTime: response.start_time
1343
1328
  });
1344
- return result;
1329
+ return { data, error: null };
1345
1330
  }
1346
1331
  /**
1347
1332
  * Retrieves usage statistics during the current billing period.
@@ -1352,22 +1337,22 @@ class Metrics {
1352
1337
  * ```
1353
1338
  */
1354
1339
  async usage() {
1355
- const result = { data: null, error: null };
1340
+ let error = null;
1356
1341
  const response = await this.mailchannels.get("/tx/v1/usage", {
1357
1342
  onResponseError: async ({ response: response2 }) => {
1358
- result.error = getStatusError(response2);
1343
+ error = getStatusError(response2);
1359
1344
  }
1360
- }).catch((error) => {
1361
- result.error = getResultError(result, error, "Failed to fetch usage metrics.");
1345
+ }).catch((e) => {
1346
+ error ||= getResultError(e, "Failed to fetch usage metrics.");
1362
1347
  return null;
1363
1348
  });
1364
- if (!response) return result;
1365
- result.data = clean({
1349
+ if (!response) return { data: null, error };
1350
+ const data = clean({
1366
1351
  endDate: response.period_end_date,
1367
1352
  startDate: response.period_start_date,
1368
1353
  total: response.total_usage
1369
1354
  });
1370
- return result;
1355
+ return { data, error: null };
1371
1356
  }
1372
1357
  /**
1373
1358
  * Retrieves a list of senders, either sub-accounts or campaigns, with their associated message metrics. Sorted by total # of sent messages (processed + dropped). Supports optional filter for time range, and optional settings for limit, offset, and sort order. Note: senders without any messages in the given time range will not be included in the results. The default time range is from one month ago to now, and the default sort order is descending.
@@ -1380,9 +1365,9 @@ class Metrics {
1380
1365
  * ```
1381
1366
  */
1382
1367
  async senders(type, options) {
1383
- const result = { data: null, error: null };
1384
- result.error = validateLimit(options?.limit, 1e3) || validateOffset(options?.offset);
1385
- if (result.error) return result;
1368
+ let error = null;
1369
+ error = validateLimit(options?.limit, 1e3) || validateOffset(options?.offset);
1370
+ if (error) return { data: null, error };
1386
1371
  const response = await this.mailchannels.get(`/tx/v1/metrics/senders/${type}`, {
1387
1372
  query: {
1388
1373
  start_time: options?.startTime,
@@ -1392,16 +1377,16 @@ class Metrics {
1392
1377
  sort_order: options?.sortOrder
1393
1378
  },
1394
1379
  onResponseError: async ({ response: response2 }) => {
1395
- result.error = getStatusError(response2, {
1380
+ error = getStatusError(response2, {
1396
1381
  [ErrorCode.BadRequest]: "Bad Request."
1397
1382
  });
1398
1383
  }
1399
- }).catch((error) => {
1400
- result.error = getResultError(result, error, "Failed to fetch senders metrics.");
1384
+ }).catch((e) => {
1385
+ error ||= getResultError(e, "Failed to fetch senders metrics.");
1401
1386
  return null;
1402
1387
  });
1403
- if (!response) return result;
1404
- result.data = clean({
1388
+ if (!response) return { data: null, error };
1389
+ const data = clean({
1405
1390
  endTime: response.end_time,
1406
1391
  limit: response.limit,
1407
1392
  offset: response.offset,
@@ -1409,7 +1394,7 @@ class Metrics {
1409
1394
  startTime: response.start_time,
1410
1395
  total: response.total
1411
1396
  });
1412
- return result;
1397
+ return { data, error: null };
1413
1398
  }
1414
1399
  }
1415
1400
 
@@ -1428,7 +1413,7 @@ class Suppressions {
1428
1413
  * });
1429
1414
  */
1430
1415
  async create(options) {
1431
- const result = { success: false, error: null };
1416
+ let error = null;
1432
1417
  const { addToSubAccounts, entries } = options;
1433
1418
  const payload = {
1434
1419
  add_to_sub_accounts: addToSubAccounts,
@@ -1441,22 +1426,17 @@ class Suppressions {
1441
1426
  };
1442
1427
  await this.mailchannels.post("/tx/v1/suppression-list", {
1443
1428
  body: payload,
1444
- ignoreResponseError: true,
1445
- onResponse: async ({ response }) => {
1446
- if (response.ok) {
1447
- result.success = true;
1448
- return;
1449
- }
1450
- result.error = getStatusError(response, {
1429
+ onResponseError: async ({ response }) => {
1430
+ error = getStatusError(response, {
1451
1431
  [ErrorCode.BadRequest]: "Bad Request.",
1452
1432
  [ErrorCode.Conflict]: "Conflict. One or more suppression entries in the request already exist and cannot be created again.",
1453
1433
  [ErrorCode.PayloadTooLarge]: "Payload too large. The request exceeds the maximum allowed total of 1000 suppression entries for the parent account and/or its sub-accounts."
1454
1434
  });
1455
1435
  }
1456
- }).catch((error) => {
1457
- result.error = getResultError(result, error, "Failed to create suppression entries.");
1436
+ }).catch((e) => {
1437
+ error ||= getResultError(e, "Failed to create suppression entries.");
1458
1438
  });
1459
- return result;
1439
+ return { success: !error, error };
1460
1440
  }
1461
1441
  /**
1462
1442
  * Deletes suppression entry associated with the account based on the specified recipient and source.
@@ -1469,25 +1449,20 @@ class Suppressions {
1469
1449
  * ```
1470
1450
  */
1471
1451
  async delete(recipient, source) {
1472
- const result = { success: false, error: null };
1452
+ let error = null;
1473
1453
  await this.mailchannels.delete(`/tx/v1/suppression-list/recipients/${recipient}`, {
1474
1454
  query: {
1475
1455
  source
1476
1456
  },
1477
- ignoreResponseError: true,
1478
- onResponse: async ({ response }) => {
1479
- if (response.ok) {
1480
- result.success = true;
1481
- return;
1482
- }
1483
- result.error = getStatusError(response, {
1457
+ onResponseError: async ({ response }) => {
1458
+ error = getStatusError(response, {
1484
1459
  [ErrorCode.BadRequest]: "Bad Request."
1485
1460
  });
1486
1461
  }
1487
- }).catch((error) => {
1488
- result.error = getResultError(result, error, "Failed to delete suppression entry.");
1462
+ }).catch((e) => {
1463
+ error ||= getResultError(e, "Failed to delete suppression entry.");
1489
1464
  });
1490
- return result;
1465
+ return { success: !error, error };
1491
1466
  }
1492
1467
  /**
1493
1468
  * Retrieve suppression entries associated with the specified account. Supports filtering by recipient, source and creation date range. The response is paginated, with a default limit of `1000` entries per page and an offset of `0`.
@@ -1499,9 +1474,9 @@ class Suppressions {
1499
1474
  * @param options - Options to filter and customize the suppression entries retrieval.
1500
1475
  */
1501
1476
  async list(options) {
1502
- const result = { data: null, error: null };
1503
- result.error = validateLimit(options?.limit, 1e3) || validateOffset(options?.offset);
1504
- if (result.error) return result;
1477
+ let error = null;
1478
+ error = validateLimit(options?.limit, 1e3) || validateOffset(options?.offset);
1479
+ if (error) return { data: null, error };
1505
1480
  const payload = {
1506
1481
  recipient: options?.recipient,
1507
1482
  source: options?.source,
@@ -1513,16 +1488,16 @@ class Suppressions {
1513
1488
  const response = await this.mailchannels.get("/tx/v1/suppression-list", {
1514
1489
  query: payload,
1515
1490
  onResponseError: async ({ response: response2 }) => {
1516
- result.error = getStatusError(response2, {
1491
+ error = getStatusError(response2, {
1517
1492
  [ErrorCode.BadRequest]: "Bad Request."
1518
1493
  });
1519
1494
  }
1520
- }).catch((error) => {
1521
- result.error = getResultError(result, error, "Failed to fetch suppression entries.");
1495
+ }).catch((e) => {
1496
+ error ||= getResultError(e, "Failed to fetch suppression entries.");
1522
1497
  return null;
1523
1498
  });
1524
- if (!response) return result;
1525
- result.data = clean(response.suppression_list.map((entry) => ({
1499
+ if (!response) return { data: null, error };
1500
+ const data = clean(response.suppression_list.map((entry) => ({
1526
1501
  createdAt: entry.created_at,
1527
1502
  notes: entry.notes,
1528
1503
  recipient: entry.recipient,
@@ -1530,7 +1505,7 @@ class Suppressions {
1530
1505
  source: entry.source,
1531
1506
  types: entry.suppression_types
1532
1507
  })));
1533
- return result;
1508
+ return { data, error: null };
1534
1509
  }
1535
1510
  }
1536
1511
 
@@ -1551,8 +1526,8 @@ class Domains {
1551
1526
  * ```
1552
1527
  */
1553
1528
  async provision(options) {
1529
+ let error = null;
1554
1530
  const { associateKey, overwrite, ...payload } = options;
1555
- const result = { data: null, error: null };
1556
1531
  const response = await this.mailchannels.post("/inbound/v1/domains", {
1557
1532
  query: {
1558
1533
  "associate-key": associateKey,
@@ -1560,18 +1535,19 @@ class Domains {
1560
1535
  },
1561
1536
  body: payload,
1562
1537
  onResponseError: async ({ response: response2 }) => {
1563
- result.error = getStatusError(response2, {
1538
+ error = getStatusError(response2, {
1564
1539
  [ErrorCode.BadRequest]: "Bad Request, returned in the case that an error occurs while converting an A-label domain to a U-label domain name.",
1565
1540
  [ErrorCode.Forbidden]: "The limit on associated domains is reached or you are attempting to associate a domain with a subscription that is not your own.",
1566
1541
  [ErrorCode.Conflict]: `The domain '${options.domain}' is already provisioned, and is associated with a different customer.`
1567
1542
  });
1568
1543
  }
1569
- }).catch((error) => {
1570
- result.error = getResultError(result, error, "Failed to provision domain.");
1544
+ }).catch((e) => {
1545
+ error ||= getResultError(e, "Failed to provision domain.");
1571
1546
  return null;
1572
1547
  });
1573
- result.data = clean(response);
1574
- return result;
1548
+ if (!response) return { data: null, error };
1549
+ const data = clean(response);
1550
+ return { data, error: null };
1575
1551
  }
1576
1552
  /**
1577
1553
  * Provision up to 1000 domains to use MailChannels Inbound.
@@ -1594,15 +1570,15 @@ class Domains {
1594
1570
  * ```
1595
1571
  */
1596
1572
  async bulkProvision(options, domains) {
1573
+ let error = null;
1597
1574
  const { associateKey, overwrite, subscriptionHandle } = options;
1598
- const result = { data: null, error: null };
1599
1575
  if (!domains || !domains.length) {
1600
- result.error = "No domains provided.";
1601
- return result;
1576
+ error = createError("No domains provided.");
1577
+ return { data: null, error };
1602
1578
  }
1603
1579
  if (domains.length > 1e3) {
1604
- result.error = "The maximum number of domains to be provisioned is 1000.";
1605
- return result;
1580
+ error = createError("The maximum number of domains to be provisioned is 1000.");
1581
+ return { data: null, error };
1606
1582
  }
1607
1583
  const response = await this.mailchannels.post("/inbound/v1/domains/batch", {
1608
1584
  query: {
@@ -1612,18 +1588,18 @@ class Domains {
1612
1588
  },
1613
1589
  body: { domains },
1614
1590
  onResponseError: async ({ response: response2 }) => {
1615
- result.error = getStatusError(response2, {
1591
+ error = getStatusError(response2, {
1616
1592
  [ErrorCode.BadRequest]: "Bad Request, returned in the case that a domain name fails RFC 5891 validation.",
1617
1593
  [ErrorCode.Forbidden]: "The limit on associated domains is reached or you are attempting to associate a domain with a subscription that is not your own."
1618
1594
  });
1619
1595
  }
1620
- }).catch((error) => {
1621
- result.error = getResultError(result, error, "Failed to provision domains.");
1596
+ }).catch((e) => {
1597
+ error ||= getResultError(e, "Failed to provision domains.");
1622
1598
  return null;
1623
1599
  });
1624
- if (!response) return result;
1625
- result.data = clean(response);
1626
- return result;
1600
+ if (!response) return { data: null, error };
1601
+ const data = clean(response);
1602
+ return { data, error: null };
1627
1603
  }
1628
1604
  /**
1629
1605
  * Fetch a list of all domains associated with this API key.
@@ -1635,24 +1611,24 @@ class Domains {
1635
1611
  * ```
1636
1612
  */
1637
1613
  async list(options) {
1638
- const result = { data: null, error: null };
1639
- result.error = validateLimit(options?.limit, 5e3) || validateOffset(options?.offset);
1640
- if (result.error) return result;
1614
+ let error = null;
1615
+ error = validateLimit(options?.limit, 5e3) || validateOffset(options?.offset);
1616
+ if (error) return { data: null, error };
1641
1617
  const response = await this.mailchannels.get("/inbound/v1/domains", {
1642
1618
  query: options,
1643
1619
  onResponseError: async ({ response: response2 }) => {
1644
- result.error = getStatusError(response2);
1620
+ error = getStatusError(response2);
1645
1621
  }
1646
- }).catch((error) => {
1647
- result.error = getResultError(result, error, "Failed to fetch domains.");
1622
+ }).catch((e) => {
1623
+ error ||= getResultError(e, "Failed to fetch domains.");
1648
1624
  return null;
1649
1625
  });
1650
- if (!response) return result;
1651
- result.data = clean({
1626
+ if (!response) return { data: null, error };
1627
+ const data = clean({
1652
1628
  domains: response.domains,
1653
1629
  total: response.total
1654
1630
  });
1655
- return result;
1631
+ return { data, error: null };
1656
1632
  }
1657
1633
  /**
1658
1634
  * De-provision a domain to cease protecting it with MailChannels Inbound.
@@ -1664,27 +1640,22 @@ class Domains {
1664
1640
  * ```
1665
1641
  */
1666
1642
  async delete(domain) {
1667
- const result = { success: false, error: null };
1643
+ let error = null;
1668
1644
  if (!domain) {
1669
- result.error = "No domain provided.";
1670
- return result;
1645
+ error = createError("No domain provided.");
1646
+ return { success: false, error };
1671
1647
  }
1672
1648
  await this.mailchannels.delete(`/inbound/v1/domains/${domain}`, {
1673
- ignoreResponseError: true,
1674
- onResponse: async ({ response }) => {
1675
- if (response.ok) {
1676
- result.success = true;
1677
- return;
1678
- }
1679
- result.error = getStatusError(response, {
1649
+ onResponseError: async ({ response }) => {
1650
+ error = getStatusError(response, {
1680
1651
  [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, or the domain in the request is an alias domain.",
1681
1652
  [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
1682
1653
  });
1683
1654
  }
1684
- }).catch((error) => {
1685
- result.error = getResultError(result, error, "Failed to delete domain.");
1655
+ }).catch((e) => {
1656
+ error ||= getResultError(e, "Failed to delete domain.");
1686
1657
  });
1687
- return result;
1658
+ return { success: !error, error };
1688
1659
  }
1689
1660
  /**
1690
1661
  * Add an entry to a domain blocklist or safelist.
@@ -1701,34 +1672,34 @@ class Domains {
1701
1672
  */
1702
1673
  async addListEntry(domain, options) {
1703
1674
  const { listName, item } = options;
1704
- const result = { data: null, error: null };
1675
+ let error = null;
1705
1676
  if (!domain) {
1706
- result.error = "No domain provided.";
1707
- return result;
1677
+ error = createError("No domain provided.");
1678
+ return { data: null, error };
1708
1679
  }
1709
1680
  if (!listName) {
1710
- result.error = "No list name provided.";
1711
- return result;
1681
+ error = createError("No list name provided.");
1682
+ return { data: null, error };
1712
1683
  }
1713
1684
  const response = await this.mailchannels.post(`/inbound/v1/domains/${domain}/lists/${listName}`, {
1714
1685
  body: { item },
1715
1686
  onResponseError: async ({ response: response2 }) => {
1716
- result.error = getStatusError(response2, {
1687
+ error = getStatusError(response2, {
1717
1688
  [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
1718
1689
  [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
1719
1690
  });
1720
1691
  }
1721
- }).catch((error) => {
1722
- result.error = getResultError(result, error, "Failed to add domain list entry.");
1692
+ }).catch((e) => {
1693
+ error ||= getResultError(e, "Failed to add domain list entry.");
1723
1694
  return null;
1724
1695
  });
1725
- if (!response) return result;
1726
- result.data = clean({
1696
+ if (!response) return { data: null, error };
1697
+ const data = clean({
1727
1698
  action: response.action,
1728
1699
  item: response.item,
1729
1700
  type: response.item_type
1730
1701
  });
1731
- return result;
1702
+ return { data, error: null };
1732
1703
  }
1733
1704
  /**
1734
1705
  * Get domain list entries.
@@ -1741,33 +1712,33 @@ class Domains {
1741
1712
  * ```
1742
1713
  */
1743
1714
  async listEntries(domain, listName) {
1744
- const result = { data: null, error: null };
1715
+ let error = null;
1745
1716
  if (!domain) {
1746
- result.error = "No domain provided.";
1747
- return result;
1717
+ error = createError("No domain provided.");
1718
+ return { data: null, error };
1748
1719
  }
1749
1720
  if (!listName) {
1750
- result.error = "No list name provided.";
1751
- return result;
1721
+ error = createError("No list name provided.");
1722
+ return { data: null, error };
1752
1723
  }
1753
1724
  const response = await this.mailchannels.get(`/inbound/v1/domains/${domain}/lists/${listName}`, {
1754
1725
  onResponseError: async ({ response: response2 }) => {
1755
- result.error = getStatusError(response2, {
1726
+ error = getStatusError(response2, {
1756
1727
  [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
1757
1728
  [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
1758
1729
  });
1759
1730
  }
1760
- }).catch((error) => {
1761
- result.error = getResultError(result, error, "Failed to fetch domain list entries.");
1731
+ }).catch((e) => {
1732
+ error ||= getResultError(e, "Failed to fetch domain list entries.");
1762
1733
  return null;
1763
1734
  });
1764
- if (!response) return result;
1765
- result.data = clean(response.map(({ action, item, item_type }) => ({
1735
+ if (!response) return { data: null, error };
1736
+ const data = clean(response.map(({ action, item, item_type }) => ({
1766
1737
  action,
1767
1738
  item,
1768
1739
  type: item_type
1769
1740
  })));
1770
- return result;
1741
+ return { data, error: null };
1771
1742
  }
1772
1743
  /**
1773
1744
  * Delete item from domain list.
@@ -1784,32 +1755,27 @@ class Domains {
1784
1755
  */
1785
1756
  async deleteListEntry(domain, options) {
1786
1757
  const { listName, item } = options;
1787
- const result = { success: false, error: null };
1758
+ let error = null;
1788
1759
  if (!domain) {
1789
- result.error = "No domain provided.";
1790
- return result;
1760
+ error = createError("No domain provided.");
1761
+ return { success: false, error };
1791
1762
  }
1792
1763
  if (!listName) {
1793
- result.error = "No list name provided.";
1794
- return result;
1764
+ error = createError("No list name provided.");
1765
+ return { success: false, error };
1795
1766
  }
1796
1767
  await this.mailchannels.delete(`/inbound/v1/domains/${domain}/lists/${listName}`, {
1797
1768
  query: { item },
1798
- ignoreResponseError: true,
1799
- onResponse: async ({ response }) => {
1800
- if (response.ok) {
1801
- result.success = true;
1802
- return;
1803
- }
1804
- result.error = getStatusError(response, {
1769
+ onResponseError: async ({ response }) => {
1770
+ error = getStatusError(response, {
1805
1771
  [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
1806
1772
  [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
1807
1773
  });
1808
1774
  }
1809
- }).catch((error) => {
1810
- result.error = getResultError(result, error, "Failed to delete domain list entry.");
1775
+ }).catch((e) => {
1776
+ error ||= getResultError(e, "Failed to delete domain list entry.");
1811
1777
  });
1812
- return result;
1778
+ return { success: !error, error };
1813
1779
  }
1814
1780
  /**
1815
1781
  * Generate a link that allows a user to log in as a domain administrator.
@@ -1821,28 +1787,28 @@ class Domains {
1821
1787
  * ```
1822
1788
  */
1823
1789
  async createLoginLink(domain) {
1824
- const result = { data: null, error: null };
1790
+ let error = null;
1825
1791
  if (!domain) {
1826
- result.error = "No domain provided.";
1827
- return result;
1792
+ error = createError("No domain provided.");
1793
+ return { data: null, error };
1828
1794
  }
1829
1795
  const response = await this.mailchannels.get(`/inbound/v1/domains/${domain}/login-link`, {
1830
1796
  onResponseError: async ({ response: response2 }) => {
1831
- result.error = getStatusError(response2, {
1797
+ error = getStatusError(response2, {
1832
1798
  [ErrorCode.Unauthorized]: "The domain does not belong to this customer.",
1833
1799
  [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
1834
1800
  [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
1835
1801
  });
1836
1802
  }
1837
- }).catch((error) => {
1838
- result.error = getResultError(result, error, "Failed to create login link.");
1803
+ }).catch((e) => {
1804
+ error ||= getResultError(e, "Failed to create login link.");
1839
1805
  return null;
1840
1806
  });
1841
- if (!response) return result;
1842
- result.data = clean({
1807
+ if (!response) return { data: null, error };
1808
+ const data = clean({
1843
1809
  link: response.loginLink
1844
1810
  });
1845
- return result;
1811
+ return { data, error: null };
1846
1812
  }
1847
1813
  /**
1848
1814
  * Sets the list of downstream addresses for the domain. This action deletes any existing downstream address for the domain before creating new ones. If the `records` parameter is an empty array, all downstream address records will be deleted.
@@ -1862,32 +1828,27 @@ class Domains {
1862
1828
  * ```
1863
1829
  */
1864
1830
  async setDownstreamAddress(domain, records = []) {
1865
- const result = { success: false, error: null };
1831
+ let error = null;
1866
1832
  if (!domain) {
1867
- result.error = "No domain provided.";
1868
- return result;
1833
+ error = createError("No domain provided.");
1834
+ return { success: false, error };
1869
1835
  }
1870
1836
  if (records.length > 10) {
1871
- result.error = "The maximum of records to be set is 10.";
1872
- return result;
1837
+ error = createError("The maximum of records to be set is 10.");
1838
+ return { success: false, error };
1873
1839
  }
1874
1840
  await this.mailchannels.put(`/inbound/v1/domains/${domain}/downstream-address`, {
1875
1841
  body: { records },
1876
- ignoreResponseError: true,
1877
- onResponse: async ({ response }) => {
1878
- if (response.ok) {
1879
- result.success = true;
1880
- return;
1881
- }
1882
- result.error = getStatusError(response, {
1842
+ onResponseError: async ({ response }) => {
1843
+ error = getStatusError(response, {
1883
1844
  [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
1884
1845
  [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
1885
1846
  });
1886
1847
  }
1887
- }).catch((error) => {
1888
- result.error = getResultError(result, error, "Failed to set downstream address.");
1848
+ }).catch((e) => {
1849
+ error ||= getResultError(e, "Failed to set downstream address.");
1889
1850
  });
1890
- return result;
1851
+ return { success: !error, error };
1891
1852
  }
1892
1853
  /**
1893
1854
  * Retrieve stored downstream addresses for the domain.
@@ -1900,28 +1861,28 @@ class Domains {
1900
1861
  * ```
1901
1862
  */
1902
1863
  async listDownstreamAddresses(domain, options) {
1903
- const result = { data: null, error: null };
1864
+ let error = null;
1904
1865
  if (!domain) {
1905
- result.error = "No domain provided.";
1906
- return result;
1866
+ error = createError("No domain provided.");
1867
+ return { data: null, error };
1907
1868
  }
1908
- result.error = validateLimit(options?.limit) || validateOffset(options?.offset);
1909
- if (result.error) return result;
1869
+ error = validateLimit(options?.limit) || validateOffset(options?.offset);
1870
+ if (error) return { data: null, error };
1910
1871
  const response = await this.mailchannels.get(`/inbound/v1/domains/${domain}/downstream-address`, {
1911
1872
  query: options,
1912
1873
  onResponseError: async ({ response: response2 }) => {
1913
- result.error = getStatusError(response2, {
1874
+ error = getStatusError(response2, {
1914
1875
  [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
1915
1876
  [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
1916
1877
  });
1917
1878
  }
1918
- }).catch((error) => {
1919
- result.error = getResultError(result, error, "Failed to list downstream addresses.");
1879
+ }).catch((e) => {
1880
+ error ||= getResultError(e, "Failed to list downstream addresses.");
1920
1881
  return null;
1921
1882
  });
1922
- if (!response) return result;
1923
- result.data = clean(response.records);
1924
- return result;
1883
+ if (!response) return { data: null, error };
1884
+ const data = clean(response.records);
1885
+ return { data, error: null };
1925
1886
  }
1926
1887
  /**
1927
1888
  * Update the API key that is associated with a domain.
@@ -1934,32 +1895,27 @@ class Domains {
1934
1895
  * ```
1935
1896
  */
1936
1897
  async updateApiKey(domain, key) {
1937
- const result = { success: false, error: null };
1898
+ let error = null;
1938
1899
  if (!domain) {
1939
- result.error = "No domain provided.";
1940
- return result;
1900
+ error = createError("No domain provided.");
1901
+ return { success: false, error };
1941
1902
  }
1942
1903
  if (!key) {
1943
- result.error = "No API key provided.";
1944
- return result;
1904
+ error = createError("No API key provided.");
1905
+ return { success: false, error };
1945
1906
  }
1946
1907
  await this.mailchannels.put(`/inbound/v1/domains/${domain}/api-key`, {
1947
1908
  body: { apiKey: key },
1948
- ignoreResponseError: true,
1949
- onResponse: async ({ response }) => {
1950
- if (response.ok) {
1951
- result.success = true;
1952
- return;
1953
- }
1954
- result.error = getStatusError(response, {
1909
+ onResponseError: async ({ response }) => {
1910
+ error = getStatusError(response, {
1955
1911
  [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
1956
1912
  [ErrorCode.NotFound]: "The domain does not exist."
1957
1913
  });
1958
1914
  }
1959
- }).catch((error) => {
1960
- result.error = getResultError(result, error, "Failed to update domain API key.");
1915
+ }).catch((e) => {
1916
+ error ||= getResultError(e, "Failed to update domain API key.");
1961
1917
  });
1962
- return result;
1918
+ return { success: !error, error };
1963
1919
  }
1964
1920
  /**
1965
1921
  * Generate a batch of links that allow a user to log in as a domain administrator to their different domains.
@@ -1971,31 +1927,31 @@ class Domains {
1971
1927
  * ```
1972
1928
  */
1973
1929
  async bulkCreateLoginLinks(domains) {
1974
- const result = { data: null, error: null };
1930
+ let error = null;
1975
1931
  if (!domains || !domains.length) {
1976
- result.error = "No domains provided.";
1977
- return result;
1932
+ error = createError("No domains provided.");
1933
+ return { data: null, error };
1978
1934
  }
1979
1935
  if (domains.length > 1e3) {
1980
- result.error = "The maximum number of domains to create login links for is 1000.";
1981
- return result;
1936
+ error = createError("The maximum number of domains to create login links for is 1000.");
1937
+ return { data: null, error };
1982
1938
  }
1983
1939
  const response = await this.mailchannels.post("/inbound/v1/domains/batch/login-link", {
1984
1940
  body: {
1985
1941
  domains: domains.map((domain) => ({ domain }))
1986
1942
  },
1987
1943
  onResponseError: async ({ response: response2 }) => {
1988
- result.error = getStatusError(response2, {
1944
+ error = getStatusError(response2, {
1989
1945
  [ErrorCode.BadRequest]: "Bad Request."
1990
1946
  });
1991
1947
  }
1992
- }).catch((error) => {
1993
- result.error = getResultError(result, error, "Failed to create login links.");
1948
+ }).catch((e) => {
1949
+ error ||= getResultError(e, "Failed to create login links.");
1994
1950
  return null;
1995
1951
  });
1996
- if (!response) return result;
1997
- result.data = clean(response);
1998
- return result;
1952
+ if (!response) return { data: null, error };
1953
+ const data = clean(response);
1954
+ return { data, error: null };
1999
1955
  }
2000
1956
  }
2001
1957
 
@@ -2016,28 +1972,28 @@ class Lists {
2016
1972
  * ```
2017
1973
  */
2018
1974
  async addListEntry(options) {
1975
+ let error = null;
2019
1976
  const { listName, item } = options;
2020
- const result = { data: null, error: null };
2021
1977
  if (!listName) {
2022
- result.error = "No list name provided.";
2023
- return result;
1978
+ error = createError("No list name provided.");
1979
+ return { data: null, error };
2024
1980
  }
2025
1981
  const response = await this.mailchannels.post(`/inbound/v1/lists/${listName}`, {
2026
1982
  body: { item },
2027
1983
  onResponseError: async ({ response: response2 }) => {
2028
- result.error = getStatusError(response2);
1984
+ error = getStatusError(response2);
2029
1985
  }
2030
- }).catch((error) => {
2031
- result.error = getResultError(result, error, "Failed to add list entry.");
1986
+ }).catch((e) => {
1987
+ error ||= getResultError(e, "Failed to add list entry.");
2032
1988
  return null;
2033
1989
  });
2034
- if (!response) return result;
2035
- result.data = clean({
1990
+ if (!response) return { data: null, error };
1991
+ const data = clean({
2036
1992
  action: response.action,
2037
1993
  item: response.item,
2038
1994
  type: response.item_type
2039
1995
  });
2040
- return result;
1996
+ return { data, error: null };
2041
1997
  }
2042
1998
  /**
2043
1999
  * Get account-level list entries.
@@ -2049,26 +2005,26 @@ class Lists {
2049
2005
  * ```
2050
2006
  */
2051
2007
  async listEntries(listName) {
2052
- const result = { data: null, error: null };
2008
+ let error = null;
2053
2009
  if (!listName) {
2054
- result.error = "No list name provided.";
2055
- return result;
2010
+ error = createError("No list name provided.");
2011
+ return { data: null, error };
2056
2012
  }
2057
2013
  const response = await this.mailchannels.get(`/inbound/v1/lists/${listName}`, {
2058
2014
  onResponseError: async ({ response: response2 }) => {
2059
- result.error = getStatusError(response2);
2015
+ error = getStatusError(response2);
2060
2016
  }
2061
- }).catch((error) => {
2062
- result.error = getResultError(result, error, "Failed to fetch list entries.");
2017
+ }).catch((e) => {
2018
+ error ||= getResultError(e, "Failed to fetch list entries.");
2063
2019
  return null;
2064
2020
  });
2065
- if (!response) return result;
2066
- result.data = clean(response.map(({ action, item, item_type }) => ({
2021
+ if (!response) return { data: null, error };
2022
+ const data = clean(response.map(({ action, item, item_type }) => ({
2067
2023
  action,
2068
2024
  item,
2069
2025
  type: item_type
2070
2026
  })));
2071
- return result;
2027
+ return { data, error: null };
2072
2028
  }
2073
2029
  /**
2074
2030
  * Delete item from account-level list.
@@ -2084,25 +2040,20 @@ class Lists {
2084
2040
  */
2085
2041
  async deleteListEntry(options) {
2086
2042
  const { listName, item } = options;
2087
- const result = { success: false, error: null };
2043
+ let error = null;
2088
2044
  if (!listName) {
2089
- result.error = "No list name provided.";
2090
- return result;
2045
+ error = createError("No list name provided.");
2046
+ return { success: false, error };
2091
2047
  }
2092
2048
  await this.mailchannels.delete(`/inbound/v1/lists/${listName}`, {
2093
2049
  query: { item },
2094
- ignoreResponseError: true,
2095
- onResponse: async ({ response }) => {
2096
- if (response.ok) {
2097
- result.success = true;
2098
- return;
2099
- }
2100
- result.error = getStatusError(response);
2050
+ onResponseError: async ({ response }) => {
2051
+ error = getStatusError(response);
2101
2052
  }
2102
- }).catch((error) => {
2103
- result.error = getResultError(result, error, "Failed to delete list entry.");
2053
+ }).catch((e) => {
2054
+ error ||= getResultError(e, "Failed to delete list entry.");
2104
2055
  });
2105
- return result;
2056
+ return { success: !error, error };
2106
2057
  }
2107
2058
  }
2108
2059
 
@@ -2124,10 +2075,10 @@ class Users {
2124
2075
  */
2125
2076
  async create(email, options) {
2126
2077
  const { admin, filter, listEntries } = options || {};
2127
- const result = { data: null, error: null };
2078
+ let error = null;
2128
2079
  if (!email) {
2129
- result.error = "No email address provided.";
2130
- return result;
2080
+ error = createError("No email address provided.");
2081
+ return { data: null, error };
2131
2082
  }
2132
2083
  const response = await this.mailchannels.put("/inbound/v1/users", {
2133
2084
  query: {
@@ -2139,16 +2090,16 @@ class Users {
2139
2090
  list_entries: listEntries
2140
2091
  },
2141
2092
  onResponseError: async ({ response: response2 }) => {
2142
- result.error = getStatusError(response2, {
2093
+ error = getStatusError(response2, {
2143
2094
  [ErrorCode.BadRequest]: `The email address '${email}' is invalid.`
2144
2095
  });
2145
2096
  }
2146
- }).catch((error) => {
2147
- result.error = getResultError(result, error, "Failed to create user.");
2097
+ }).catch((e) => {
2098
+ error ||= getResultError(e, "Failed to create user.");
2148
2099
  return null;
2149
2100
  });
2150
- if (!response) return result;
2151
- result.data = clean({
2101
+ if (!response) return { data: null, error };
2102
+ const data = clean({
2152
2103
  email: response.recipient.email_address,
2153
2104
  roles: response.recipient.roles,
2154
2105
  filter: response.recipient.filter,
@@ -2158,7 +2109,7 @@ class Users {
2158
2109
  action
2159
2110
  }))
2160
2111
  });
2161
- return result;
2112
+ return { data, error: null };
2162
2113
  }
2163
2114
  /**
2164
2115
  * Add item to recipient user list
@@ -2175,34 +2126,34 @@ class Users {
2175
2126
  */
2176
2127
  async addListEntry(email, options) {
2177
2128
  const { listName, item } = options;
2178
- const result = { data: null, error: null };
2129
+ let error = null;
2179
2130
  if (!email) {
2180
- result.error = "No email provided.";
2181
- return result;
2131
+ error = createError("No email provided.");
2132
+ return { data: null, error };
2182
2133
  }
2183
2134
  if (!listName) {
2184
- result.error = "No list name provided.";
2185
- return result;
2135
+ error = createError("No list name provided.");
2136
+ return { data: null, error };
2186
2137
  }
2187
2138
  const response = await this.mailchannels.post(`/inbound/v1/users/${email}/lists/${listName}`, {
2188
2139
  body: { item },
2189
2140
  onResponseError: async ({ response: response2 }) => {
2190
- result.error = getStatusError(response2, {
2141
+ error = getStatusError(response2, {
2191
2142
  [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
2192
2143
  [ErrorCode.NotFound]: `The recipient '${email}' was not found.`
2193
2144
  });
2194
2145
  }
2195
- }).catch((error) => {
2196
- result.error = getResultError(result, error, "Failed to add user list entry.");
2146
+ }).catch((e) => {
2147
+ error ||= getResultError(e, "Failed to add user list entry.");
2197
2148
  return null;
2198
2149
  });
2199
- if (!response) return result;
2200
- result.data = clean({
2150
+ if (!response) return { data: null, error };
2151
+ const data = clean({
2201
2152
  action: response.action,
2202
2153
  item: response.item,
2203
2154
  type: response.item_type
2204
2155
  });
2205
- return result;
2156
+ return { data, error: null };
2206
2157
  }
2207
2158
  /**
2208
2159
  * Get recipient list entries.
@@ -2215,33 +2166,33 @@ class Users {
2215
2166
  * ```
2216
2167
  */
2217
2168
  async listEntries(email, listName) {
2218
- const result = { data: null, error: null };
2169
+ let error = null;
2219
2170
  if (!email) {
2220
- result.error = "No email provided.";
2221
- return result;
2171
+ error = createError("No email provided.");
2172
+ return { data: null, error };
2222
2173
  }
2223
2174
  if (!listName) {
2224
- result.error = "No list name provided.";
2225
- return result;
2175
+ error = createError("No list name provided.");
2176
+ return { data: null, error };
2226
2177
  }
2227
2178
  const response = await this.mailchannels.get(`/inbound/v1/users/${email}/lists/${listName}`, {
2228
2179
  onResponseError: async ({ response: response2 }) => {
2229
- result.error = getStatusError(response2, {
2180
+ error = getStatusError(response2, {
2230
2181
  [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
2231
2182
  [ErrorCode.NotFound]: `The recipient '${email}' was not found.`
2232
2183
  });
2233
2184
  }
2234
- }).catch((error) => {
2235
- result.error = getResultError(result, error, "Failed to fetch user list entries.");
2185
+ }).catch((e) => {
2186
+ error ||= getResultError(e, "Failed to fetch user list entries.");
2236
2187
  return null;
2237
2188
  });
2238
- if (!response) return result;
2239
- result.data = clean(response.map(({ action, item, item_type }) => ({
2189
+ if (!response) return { data: null, error };
2190
+ const data = clean(response.map(({ action, item, item_type }) => ({
2240
2191
  action,
2241
2192
  item,
2242
2193
  type: item_type
2243
2194
  })));
2244
- return result;
2195
+ return { data, error: null };
2245
2196
  }
2246
2197
  /**
2247
2198
  * Delete item from recipient list.
@@ -2258,32 +2209,27 @@ class Users {
2258
2209
  */
2259
2210
  async deleteListEntry(email, options) {
2260
2211
  const { listName, item } = options;
2261
- const result = { success: false, error: null };
2212
+ let error = null;
2262
2213
  if (!email) {
2263
- result.error = "No email provided.";
2264
- return result;
2214
+ error = createError("No email provided.");
2215
+ return { success: false, error };
2265
2216
  }
2266
2217
  if (!listName) {
2267
- result.error = "No list name provided.";
2268
- return result;
2218
+ error = createError("No list name provided.");
2219
+ return { success: false, error };
2269
2220
  }
2270
2221
  await this.mailchannels.delete(`/inbound/v1/users/${email}/lists/${listName}`, {
2271
2222
  query: { item },
2272
- ignoreResponseError: true,
2273
- onResponse: async ({ response }) => {
2274
- if (response.ok) {
2275
- result.success = true;
2276
- return;
2277
- }
2278
- result.error = getStatusError(response, {
2223
+ onResponseError: async ({ response }) => {
2224
+ error = getStatusError(response, {
2279
2225
  [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
2280
2226
  [ErrorCode.NotFound]: `The recipient '${email}' was not found.`
2281
2227
  });
2282
2228
  }
2283
- }).catch((error) => {
2284
- result.error = getResultError(result, error, "Failed to delete user list entry.");
2229
+ }).catch((e) => {
2230
+ error ||= getResultError(e, "Failed to delete user list entry.");
2285
2231
  });
2286
- return result;
2232
+ return { success: !error, error };
2287
2233
  }
2288
2234
  }
2289
2235
 
@@ -2300,20 +2246,15 @@ class Service {
2300
2246
  * ```
2301
2247
  */
2302
2248
  async status() {
2303
- const result = { success: false, error: null };
2249
+ let error = null;
2304
2250
  await this.mailchannels.get("/inbound/v1/status", {
2305
- ignoreResponseError: true,
2306
- onResponse: async ({ response }) => {
2307
- if (response.ok) {
2308
- result.success = true;
2309
- return;
2310
- }
2311
- result.error = getStatusError(response);
2251
+ onResponseError: async ({ response }) => {
2252
+ error = getStatusError(response);
2312
2253
  }
2313
- }).catch((error) => {
2314
- result.error = getResultError(result, error, "Failed to fetch service status.");
2254
+ }).catch((e) => {
2255
+ error ||= getResultError(e, "Failed to fetch service status.");
2315
2256
  });
2316
- return result;
2257
+ return { success: !error, error };
2317
2258
  }
2318
2259
  /**
2319
2260
  * Get a list of your subscriptions to MailChannels Inbound
@@ -2324,20 +2265,20 @@ class Service {
2324
2265
  * ```
2325
2266
  */
2326
2267
  async subscriptions() {
2327
- const result = { data: null, error: null };
2268
+ let error = null;
2328
2269
  const response = await this.mailchannels.get("/inbound/v1/subscriptions", {
2329
2270
  onResponseError: async ({ response: response2 }) => {
2330
- result.error = getStatusError(response2, {
2271
+ error = getStatusError(response2, {
2331
2272
  [ErrorCode.NotFound]: "We could not find a customer that matched the customerHandle."
2332
2273
  });
2333
2274
  }
2334
- }).catch((error) => {
2335
- result.error = getResultError(result, error, "Failed to fetch subscriptions.");
2275
+ }).catch((e) => {
2276
+ error ||= getResultError(e, "Failed to fetch subscriptions.");
2336
2277
  return null;
2337
2278
  });
2338
- if (!response) return result;
2339
- result.data = clean(response);
2340
- return result;
2279
+ if (!response) return { data: null, error };
2280
+ const data = clean(response);
2281
+ return { data, error: null };
2341
2282
  }
2342
2283
  /**
2343
2284
  * Submit a false negative or false positive report.
@@ -2351,25 +2292,20 @@ class Service {
2351
2292
  * ```
2352
2293
  */
2353
2294
  async report(options) {
2354
- const result = { success: false, error: null };
2295
+ let error = null;
2355
2296
  const { type, ...payload } = options;
2356
2297
  await this.mailchannels.post("/inbound/v1/report", {
2357
2298
  query: {
2358
2299
  report_type: type
2359
2300
  },
2360
2301
  body: payload,
2361
- ignoreResponseError: true,
2362
- onResponse: async ({ response }) => {
2363
- if (response.ok) {
2364
- result.success = true;
2365
- return;
2366
- }
2367
- result.error = getStatusError(response);
2302
+ onResponseError: async ({ response }) => {
2303
+ error = getStatusError(response);
2368
2304
  }
2369
- }).catch((error) => {
2370
- result.error = getResultError(result, error, "Failed to submit report.");
2305
+ }).catch((e) => {
2306
+ error ||= getResultError(e, "Failed to submit report.");
2371
2307
  });
2372
- return result;
2308
+ return { success: !error, error };
2373
2309
  }
2374
2310
  }
2375
2311