mailchannels-sdk 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import { $fetch } from "ofetch";
2
2
  import { subtle } from "node:crypto";
3
3
  import { Buffer } from "node:buffer";
4
4
  import mime from "mime";
5
- var version = "1.0.0";
5
+ var version = "1.1.0";
6
6
  var MailChannelsClient = class MailChannelsClient {
7
7
  static DEFAULT_BASE_URL = "https://api.mailchannels.net";
8
8
  static DEFAULT_TIMEOUT = 12e4;
@@ -160,7 +160,7 @@ const parseArrayRecipients = (recipients) => {
160
160
  return filtered.length > 0 ? filtered : void 0;
161
161
  };
162
162
  const stripPemHeaders = (pem) => pem.replace(/-----[^-]+-----|\s|#.*$/gm, "");
163
- const RESERVED_HEADER_NAMES = new Set([
163
+ const RESERVED_HEADER_NAMES = /* @__PURE__ */ new Set([
164
164
  "authentication-results",
165
165
  "bcc",
166
166
  "cc",
@@ -424,80 +424,6 @@ const mapDkimKey = (key) => ({
424
424
  status: key.status,
425
425
  statusModifiedAt: key.status_modified_at
426
426
  });
427
- var Domains = class {
428
- mailchannels;
429
- dkim;
430
- constructor(mailchannels) {
431
- this.mailchannels = mailchannels;
432
- this.dkim = new DomainsDkim(mailchannels);
433
- }
434
- async check(domain, options) {
435
- let error = null;
436
- if (!domain) {
437
- error = createValidationError("No domain provided.");
438
- return {
439
- data: null,
440
- error
441
- };
442
- }
443
- const dkimOptions = options?.dkim ? Array.isArray(options.dkim) ? options.dkim : [options.dkim] : void 0;
444
- if (dkimOptions && dkimOptions.length > 10) {
445
- error = createValidationError("A maximum of 10 DKIM settings can be provided.");
446
- return {
447
- data: null,
448
- error
449
- };
450
- }
451
- if (dkimOptions?.find(({ privateKey, selector }) => privateKey && !selector)) {
452
- error = createValidationError("DKIM settings with a privateKey must also include a selector.");
453
- return {
454
- data: null,
455
- error
456
- };
457
- }
458
- const payload = {
459
- dkim_settings: dkimOptions?.map((dkim) => ({
460
- dkim_domain: dkim.domain,
461
- dkim_private_key: dkim.privateKey ? stripPemHeaders(dkim.privateKey) : void 0,
462
- dkim_selector: dkim.selector
463
- })),
464
- domain,
465
- sender_id: options?.senderId
466
- };
467
- const response = await this.mailchannels.post("/tx/v1/check-domain", {
468
- body: payload,
469
- onResponseError: async ({ response }) => {
470
- error = getStatusError(response, {
471
- [400]: "Bad Request.",
472
- [403]: "User does not have access to this feature."
473
- });
474
- }
475
- }).catch((e) => {
476
- error ||= getResultError(e, "Failed to check domain.");
477
- return null;
478
- });
479
- if (!response) return {
480
- data: null,
481
- error
482
- };
483
- return {
484
- data: clean({
485
- dkim: response.check_results.dkim.map((dkimResults) => ({
486
- domain: dkimResults.dkim_domain,
487
- keyStatus: dkimResults.dkim_key_status,
488
- selector: dkimResults.dkim_selector,
489
- reason: dkimResults.reason,
490
- verdict: dkimResults.verdict
491
- })),
492
- domainLockdown: response.check_results.domain_lockdown,
493
- senderDomain: response.check_results.sender_domain,
494
- spf: response.check_results.spf,
495
- references: response.references
496
- }),
497
- error: null
498
- };
499
- }
500
- };
501
427
  var DomainsDkim = class {
502
428
  mailchannels;
503
429
  constructor(mailchannels) {
@@ -524,7 +450,7 @@ var DomainsDkim = class {
524
450
  key_length: options.length,
525
451
  selector: options.selector
526
452
  };
527
- const response = await this.mailchannels.post(`/tx/v1/domains/${domain}/dkim-keys`, {
453
+ const response = await this.mailchannels.post(`/tx/v1/domains/${encodeURIComponent(domain)}/dkim-keys`, {
528
454
  body: payload,
529
455
  onResponseError: async ({ response }) => {
530
456
  error = getStatusError(response, {
@@ -576,7 +502,7 @@ var DomainsDkim = class {
576
502
  limit: options?.limit,
577
503
  include_dns_record: options?.includeDnsRecord
578
504
  };
579
- const response = await this.mailchannels.get(`/tx/v1/domains/${domain}/dkim-keys`, {
505
+ const response = await this.mailchannels.get(`/tx/v1/domains/${encodeURIComponent(domain)}/dkim-keys`, {
580
506
  query: payload,
581
507
  onResponseError: async ({ response }) => {
582
508
  error = getStatusError(response, { [400]: "Bad Request." });
@@ -611,7 +537,7 @@ var DomainsDkim = class {
611
537
  };
612
538
  }
613
539
  const payload = { status: options.status };
614
- await this.mailchannels.patch(`/tx/v1/domains/${domain}/dkim-keys/${options.selector}`, {
540
+ await this.mailchannels.patch(`/tx/v1/domains/${encodeURIComponent(domain)}/dkim-keys/${encodeURIComponent(options.selector)}`, {
615
541
  body: payload,
616
542
  onResponseError: async ({ response }) => {
617
543
  error = getStatusError(response, {
@@ -651,7 +577,7 @@ var DomainsDkim = class {
651
577
  };
652
578
  }
653
579
  const payload = { new_key: { selector: options.newKey.selector } };
654
- const response = await this.mailchannels.post(`/tx/v1/domains/${domain}/dkim-keys/${selector}/rotate`, {
580
+ const response = await this.mailchannels.post(`/tx/v1/domains/${encodeURIComponent(domain)}/dkim-keys/${encodeURIComponent(selector)}/rotate`, {
655
581
  body: payload,
656
582
  onResponseError: async ({ response }) => {
657
583
  error = getStatusError(response, {
@@ -677,6 +603,80 @@ var DomainsDkim = class {
677
603
  };
678
604
  }
679
605
  };
606
+ var Domains = class {
607
+ mailchannels;
608
+ dkim;
609
+ constructor(mailchannels) {
610
+ this.mailchannels = mailchannels;
611
+ this.dkim = new DomainsDkim(mailchannels);
612
+ }
613
+ async check(domain, options) {
614
+ let error = null;
615
+ if (!domain) {
616
+ error = createValidationError("No domain provided.");
617
+ return {
618
+ data: null,
619
+ error
620
+ };
621
+ }
622
+ const dkimOptions = options?.dkim ? Array.isArray(options.dkim) ? options.dkim : [options.dkim] : void 0;
623
+ if (dkimOptions && dkimOptions.length > 10) {
624
+ error = createValidationError("A maximum of 10 DKIM settings can be provided.");
625
+ return {
626
+ data: null,
627
+ error
628
+ };
629
+ }
630
+ if (dkimOptions?.find(({ privateKey, selector }) => privateKey && !selector)) {
631
+ error = createValidationError("DKIM settings with a privateKey must also include a selector.");
632
+ return {
633
+ data: null,
634
+ error
635
+ };
636
+ }
637
+ const payload = {
638
+ dkim_settings: dkimOptions?.map((dkim) => ({
639
+ dkim_domain: dkim.domain,
640
+ dkim_private_key: dkim.privateKey ? stripPemHeaders(dkim.privateKey) : void 0,
641
+ dkim_selector: dkim.selector
642
+ })),
643
+ domain,
644
+ sender_id: options?.senderId
645
+ };
646
+ const response = await this.mailchannels.post("/tx/v1/check-domain", {
647
+ body: payload,
648
+ onResponseError: async ({ response }) => {
649
+ error = getStatusError(response, {
650
+ [400]: "Bad Request.",
651
+ [403]: "User does not have access to this feature."
652
+ });
653
+ }
654
+ }).catch((e) => {
655
+ error ||= getResultError(e, "Failed to check domain.");
656
+ return null;
657
+ });
658
+ if (!response) return {
659
+ data: null,
660
+ error
661
+ };
662
+ return {
663
+ data: clean({
664
+ dkim: response.check_results.dkim.map((dkimResults) => ({
665
+ domain: dkimResults.dkim_domain,
666
+ keyStatus: dkimResults.dkim_key_status,
667
+ selector: dkimResults.dkim_selector,
668
+ reason: dkimResults.reason,
669
+ verdict: dkimResults.verdict
670
+ })),
671
+ domainLockdown: response.check_results.domain_lockdown,
672
+ senderDomain: response.check_results.sender_domain,
673
+ spf: response.check_results.spf,
674
+ references: response.references
675
+ }),
676
+ error: null
677
+ };
678
+ }
679
+ };
680
680
  const HMAC_SHA256 = {
681
681
  name: "HMAC",
682
682
  hash: "SHA-256"
@@ -749,6 +749,35 @@ async function isValidWebhook(options) {
749
749
  const key = await subtle.importKey(format, publicKeyBuffer, ED25519, false, ["verify"]);
750
750
  return subtle.verify(ED25519.name, key, webhookSignatureBuffer, encoder.encode(signingString));
751
751
  }
752
+ const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})$/;
753
+ const ISO_DATE_ONLY_REGEX = /^\d{4}-\d{2}-\d{2}$/;
754
+ const formatDateInput = (value) => {
755
+ if (value instanceof Date) {
756
+ if (Number.isNaN(value.getTime())) return null;
757
+ return value.toISOString();
758
+ }
759
+ if (typeof value === "string") {
760
+ if (!ISO_DATE_REGEX.test(value) && !ISO_DATE_ONLY_REGEX.test(value) || Number.isNaN(Date.parse(value))) return null;
761
+ if (ISO_DATE_REGEX.test(value)) return new Date(value).toISOString();
762
+ }
763
+ return value;
764
+ };
765
+ const parseDateInputs = (options) => {
766
+ const dates = {};
767
+ const keys = Object.keys(options);
768
+ for (const key of keys) {
769
+ const formatted = formatDateInput(options?.[key]);
770
+ if (formatted === null) return {
771
+ dates: null,
772
+ error: createValidationError(`The '${key}' value is not a valid date.`)
773
+ };
774
+ dates[key] = formatted;
775
+ }
776
+ return {
777
+ dates,
778
+ error: null
779
+ };
780
+ };
752
781
  var Webhooks = class Webhooks {
753
782
  mailchannels;
754
783
  constructor(mailchannels) {
@@ -936,17 +965,17 @@ var Webhooks = class Webhooks {
936
965
  data: null,
937
966
  error: createValidationError("Status filters must be unique.")
938
967
  };
939
- if (options?.createdAfter && Number.isNaN(Date.parse(options.createdAfter))) return {
940
- data: null,
941
- error: createValidationError("createdAfter must be a valid date string.")
942
- };
943
- if (options?.createdBefore && Number.isNaN(Date.parse(options.createdBefore))) return {
968
+ const { dates, error: dateError } = parseDateInputs({
969
+ createdAfter: options?.createdAfter,
970
+ createdBefore: options?.createdBefore
971
+ });
972
+ if (!dates || dateError) return {
944
973
  data: null,
945
- error: createValidationError("createdBefore must be a valid date string.")
974
+ error: dateError
946
975
  };
947
- if (options?.createdAfter && options?.createdBefore) {
948
- const createdAfter = Date.parse(options.createdAfter);
949
- const createdBefore = Date.parse(options.createdBefore);
976
+ if (dates.createdAfter && dates.createdBefore) {
977
+ const createdAfter = Date.parse(dates.createdAfter);
978
+ const createdBefore = Date.parse(dates.createdBefore);
950
979
  const maxRangeMs = 744 * 60 * 60 * 1e3;
951
980
  if (createdBefore <= createdAfter) return {
952
981
  data: null,
@@ -959,8 +988,8 @@ var Webhooks = class Webhooks {
959
988
  }
960
989
  const response = await this.mailchannels.get("/tx/v1/webhook-batch", {
961
990
  query: {
962
- created_after: options?.createdAfter,
963
- created_before: options?.createdBefore,
991
+ created_after: dates.createdAfter,
992
+ created_before: dates.createdBefore,
964
993
  statuses: options?.statuses,
965
994
  webhook: options?.webhook,
966
995
  limit: options?.limit,
@@ -993,7 +1022,7 @@ var Webhooks = class Webhooks {
993
1022
  }
994
1023
  async resendBatch(batchId) {
995
1024
  let error = null;
996
- const response = await this.mailchannels.post(`/tx/v1/webhook-batch/${batchId}/resend`, { onResponseError: async ({ response }) => {
1025
+ const response = await this.mailchannels.post(`/tx/v1/webhook-batch/${encodeURIComponent(batchId)}/resend`, { onResponseError: async ({ response }) => {
997
1026
  error = getStatusError(response, {
998
1027
  [400]: "Bad Request. The batch ID is invalid.",
999
1028
  [404]: `The batch '${batchId}' is not found for the customer.`
@@ -1020,152 +1049,12 @@ var Webhooks = class Webhooks {
1020
1049
  };
1021
1050
  }
1022
1051
  };
1023
- var SubAccounts = class SubAccounts {
1052
+ var SubAccountsApiKeys = class {
1024
1053
  mailchannels;
1025
- static COMPANY_PATTERN = /^.{3,128}$/;
1026
- static HANDLE_PATTERN = /^[a-z0-9]{3,128}$/;
1027
1054
  constructor(mailchannels) {
1028
1055
  this.mailchannels = mailchannels;
1029
1056
  }
1030
- async create(companyName, handle) {
1031
- let error = null;
1032
- if (!SubAccounts.COMPANY_PATTERN.test(companyName)) {
1033
- error = createValidationError("Invalid company name. Company name must be between 3 and 128 characters.");
1034
- return {
1035
- data: null,
1036
- error
1037
- };
1038
- }
1039
- if (handle) {
1040
- if (!SubAccounts.HANDLE_PATTERN.test(handle)) {
1041
- error = createValidationError("Invalid handle. Sub-account handle must be between 3 and 128 characters and contain only lowercase letters and numbers.");
1042
- return {
1043
- data: null,
1044
- error
1045
- };
1046
- }
1047
- }
1048
- const response = await this.mailchannels.post("/tx/v1/sub-account", {
1049
- body: {
1050
- company_name: companyName,
1051
- handle
1052
- },
1053
- onResponseError: async ({ response }) => {
1054
- error = getStatusError(response, {
1055
- [403]: "The parent account does not have permission to create sub-accounts.",
1056
- [409]: `Sub-account with handle '${handle}' already exists.`
1057
- });
1058
- }
1059
- }).catch((e) => {
1060
- error ||= getResultError(e, "Failed to create sub-account.");
1061
- return null;
1062
- });
1063
- if (!response) return {
1064
- data: null,
1065
- error
1066
- };
1067
- return {
1068
- data: clean({
1069
- companyName: response.company_name,
1070
- enabled: response.enabled,
1071
- handle: response.handle
1072
- }),
1073
- error: null
1074
- };
1075
- }
1076
- async list(options) {
1077
- let error = null;
1078
- error = validatePagination({
1079
- ...options,
1080
- max: 1e3
1081
- });
1082
- if (error) return {
1083
- data: null,
1084
- error
1085
- };
1086
- const response = await this.mailchannels.get("/tx/v1/sub-account", {
1087
- query: options,
1088
- onResponseError: async ({ response }) => {
1089
- error = getStatusError(response);
1090
- }
1091
- }).catch((e) => {
1092
- error ||= getResultError(e, "Failed to fetch sub-accounts.");
1093
- return null;
1094
- });
1095
- if (!response) return {
1096
- data: null,
1097
- error
1098
- };
1099
- return {
1100
- data: clean(response.map((account) => ({
1101
- companyName: account.company_name,
1102
- enabled: account.enabled,
1103
- handle: account.handle
1104
- }))),
1105
- error: null
1106
- };
1107
- }
1108
- async delete(handle) {
1109
- let error = null;
1110
- if (!handle) {
1111
- error = createValidationError("No handle provided.");
1112
- return {
1113
- success: false,
1114
- error
1115
- };
1116
- }
1117
- await this.mailchannels.delete(`/tx/v1/sub-account/${handle}`, { onResponseError: async ({ response }) => {
1118
- error = getStatusError(response);
1119
- } }).catch((e) => {
1120
- error ||= getResultError(e, "Failed to delete sub-account.");
1121
- });
1122
- return {
1123
- success: !error,
1124
- error
1125
- };
1126
- }
1127
- async suspend(handle) {
1128
- let error = null;
1129
- if (!handle) {
1130
- error = createValidationError("No handle provided.");
1131
- return {
1132
- success: false,
1133
- error
1134
- };
1135
- }
1136
- await this.mailchannels.post(`/tx/v1/sub-account/${handle}/suspend`, { onResponseError: async ({ response }) => {
1137
- error = getStatusError(response, { [404]: `The specified sub-account '${handle}' does not exist.` });
1138
- } }).catch((e) => {
1139
- error ||= getResultError(e, "Failed to suspend sub-account.");
1140
- });
1141
- return {
1142
- success: !error,
1143
- error
1144
- };
1145
- }
1146
- async activate(handle) {
1147
- let error = null;
1148
- if (!handle) {
1149
- error = createValidationError("No handle provided.");
1150
- return {
1151
- success: false,
1152
- error
1153
- };
1154
- }
1155
- await this.mailchannels.post(`/tx/v1/sub-account/${handle}/activate`, { onResponseError: async ({ response }) => {
1156
- error = getStatusError(response, {
1157
- [403]: "The parent account does not have permission to activate the sub-account.",
1158
- [404]: `The specified sub-account '${handle}' does not exist.`
1159
- });
1160
- } }).catch((e) => {
1161
- error ||= getResultError(e, "Failed to activate sub-account.");
1162
- });
1163
- return {
1164
- success: !error,
1165
- error
1166
- };
1167
- }
1168
- async createApiKey(handle) {
1057
+ async create(handle) {
1169
1058
  let error = null;
1170
1059
  if (!handle) {
1171
1060
  error = createValidationError("No handle provided.");
@@ -1174,7 +1063,7 @@ var SubAccounts = class SubAccounts {
1174
1063
  error
1175
1064
  };
1176
1065
  }
1177
- const response = await this.mailchannels.post(`/tx/v1/sub-account/${handle}/api-key`, { onResponseError: async ({ response }) => {
1066
+ const response = await this.mailchannels.post(`/tx/v1/sub-account/${encodeURIComponent(handle)}/api-key`, { onResponseError: async ({ response }) => {
1178
1067
  error = getStatusError(response, {
1179
1068
  [403]: "You can't create API keys for this sub-account.",
1180
1069
  [404]: `Sub-account with handle '${handle}' not found.`,
@@ -1193,7 +1082,7 @@ var SubAccounts = class SubAccounts {
1193
1082
  error: null
1194
1083
  };
1195
1084
  }
1196
- async listApiKeys(handle, options) {
1085
+ async list(handle, options) {
1197
1086
  let error = null;
1198
1087
  if (!handle) {
1199
1088
  error = createValidationError("No handle provided.");
@@ -1210,9 +1099,12 @@ var SubAccounts = class SubAccounts {
1210
1099
  data: null,
1211
1100
  error
1212
1101
  };
1213
- const response = await this.mailchannels.get(`/tx/v1/sub-account/${handle}/api-key`, { onResponseError: async ({ response }) => {
1214
- error = getStatusError(response, { [404]: `Sub-account with handle '${handle}' not found.` });
1215
- } }).catch((e) => {
1102
+ const response = await this.mailchannels.get(`/tx/v1/sub-account/${encodeURIComponent(handle)}/api-key`, {
1103
+ query: options,
1104
+ onResponseError: async ({ response }) => {
1105
+ error = getStatusError(response, { [404]: `Sub-account with handle '${handle}' not found.` });
1106
+ }
1107
+ }).catch((e) => {
1216
1108
  error ||= getResultError(e, "Failed to fetch sub-account API keys.");
1217
1109
  return null;
1218
1110
  });
@@ -1228,7 +1120,7 @@ var SubAccounts = class SubAccounts {
1228
1120
  error: null
1229
1121
  };
1230
1122
  }
1231
- async deleteApiKey(handle, id) {
1123
+ async delete(handle, id) {
1232
1124
  let error = null;
1233
1125
  if (!handle) {
1234
1126
  error = createValidationError("No handle provided.");
@@ -1237,7 +1129,7 @@ var SubAccounts = class SubAccounts {
1237
1129
  error
1238
1130
  };
1239
1131
  }
1240
- await this.mailchannels.delete(`/tx/v1/sub-account/${handle}/api-key/${id}`, { onResponseError: async ({ response }) => {
1132
+ await this.mailchannels.delete(`/tx/v1/sub-account/${encodeURIComponent(handle)}/api-key/${encodeURIComponent(id)}`, { onResponseError: async ({ response }) => {
1241
1133
  error = getStatusError(response, { [400]: "Missing or invalid API key ID." });
1242
1134
  } }).catch((e) => {
1243
1135
  error ||= getResultError(e, "Failed to delete sub-account API key.");
@@ -1247,7 +1139,13 @@ var SubAccounts = class SubAccounts {
1247
1139
  error
1248
1140
  };
1249
1141
  }
1250
- async createSmtpPassword(handle) {
1142
+ };
1143
+ var SubAccountsSmtpPasswords = class {
1144
+ mailchannels;
1145
+ constructor(mailchannels) {
1146
+ this.mailchannels = mailchannels;
1147
+ }
1148
+ async create(handle) {
1251
1149
  let error = null;
1252
1150
  if (!handle) {
1253
1151
  error = createValidationError("No handle provided.");
@@ -1256,7 +1154,7 @@ var SubAccounts = class SubAccounts {
1256
1154
  error
1257
1155
  };
1258
1156
  }
1259
- const response = await this.mailchannels.post(`/tx/v1/sub-account/${handle}/smtp-password`, { onResponseError: async ({ response }) => {
1157
+ const response = await this.mailchannels.post(`/tx/v1/sub-account/${encodeURIComponent(handle)}/smtp-password`, { onResponseError: async ({ response }) => {
1260
1158
  error = getStatusError(response, {
1261
1159
  [403]: "You can't create SMTP passwords for this sub-account.",
1262
1160
  [404]: `Sub-account with handle '${handle}' not found.`,
@@ -1279,7 +1177,7 @@ var SubAccounts = class SubAccounts {
1279
1177
  error: null
1280
1178
  };
1281
1179
  }
1282
- async listSmtpPasswords(handle) {
1180
+ async list(handle) {
1283
1181
  let error = null;
1284
1182
  if (!handle) {
1285
1183
  error = createValidationError("No handle provided.");
@@ -1288,7 +1186,7 @@ var SubAccounts = class SubAccounts {
1288
1186
  error
1289
1187
  };
1290
1188
  }
1291
- const response = await this.mailchannels.get(`/tx/v1/sub-account/${handle}/smtp-password`, { onResponseError: async ({ response }) => {
1189
+ const response = await this.mailchannels.get(`/tx/v1/sub-account/${encodeURIComponent(handle)}/smtp-password`, { onResponseError: async ({ response }) => {
1292
1190
  error = getStatusError(response, { [404]: `Sub-account with handle '${handle}' not found.` });
1293
1191
  } }).catch((e) => {
1294
1192
  error ||= getResultError(e, "Failed to fetch sub-account SMTP passwords.");
@@ -1307,7 +1205,7 @@ var SubAccounts = class SubAccounts {
1307
1205
  error: null
1308
1206
  };
1309
1207
  }
1310
- async deleteSmtpPassword(handle, id) {
1208
+ async delete(handle, id) {
1311
1209
  let error = null;
1312
1210
  if (!handle) {
1313
1211
  error = createValidationError("No handle provided.");
@@ -1316,7 +1214,7 @@ var SubAccounts = class SubAccounts {
1316
1214
  error
1317
1215
  };
1318
1216
  }
1319
- await this.mailchannels.delete(`/tx/v1/sub-account/${handle}/smtp-password/${id}`, { onResponseError: async ({ response }) => {
1217
+ await this.mailchannels.delete(`/tx/v1/sub-account/${encodeURIComponent(handle)}/smtp-password/${encodeURIComponent(id)}`, { onResponseError: async ({ response }) => {
1320
1218
  error = getStatusError(response, { [400]: "Missing or invalid SMTP password ID." });
1321
1219
  } }).catch((e) => {
1322
1220
  error ||= getResultError(e, "Failed to delete sub-account SMTP password.");
@@ -1326,7 +1224,13 @@ var SubAccounts = class SubAccounts {
1326
1224
  error
1327
1225
  };
1328
1226
  }
1329
- async getLimit(handle) {
1227
+ };
1228
+ var SubAccountsLimits = class {
1229
+ mailchannels;
1230
+ constructor(mailchannels) {
1231
+ this.mailchannels = mailchannels;
1232
+ }
1233
+ async get(handle) {
1330
1234
  let error = null;
1331
1235
  if (!handle) {
1332
1236
  error = createValidationError("No handle provided.");
@@ -1335,7 +1239,7 @@ var SubAccounts = class SubAccounts {
1335
1239
  error
1336
1240
  };
1337
1241
  }
1338
- const response = await this.mailchannels.get(`/tx/v1/sub-account/${handle}/limit`, { onResponseError: async ({ response }) => {
1242
+ const response = await this.mailchannels.get(`/tx/v1/sub-account/${encodeURIComponent(handle)}/limit`, { onResponseError: async ({ response }) => {
1339
1243
  error = getStatusError(response, { [404]: `Sub-account with handle '${handle}' not found.` });
1340
1244
  } }).catch((e) => {
1341
1245
  error ||= getResultError(e, "Failed to fetch sub-account limit.");
@@ -1350,7 +1254,7 @@ var SubAccounts = class SubAccounts {
1350
1254
  error: null
1351
1255
  };
1352
1256
  }
1353
- async setLimit(handle, limit) {
1257
+ async set(handle, options) {
1354
1258
  let error = null;
1355
1259
  if (!handle) {
1356
1260
  error = createValidationError("No handle provided.");
@@ -1359,15 +1263,15 @@ var SubAccounts = class SubAccounts {
1359
1263
  error
1360
1264
  };
1361
1265
  }
1362
- if (limit.sends < 0) {
1266
+ if (options.sends < 0) {
1363
1267
  error = createValidationError("The sends value must be at least 0.");
1364
1268
  return {
1365
1269
  success: false,
1366
1270
  error
1367
1271
  };
1368
1272
  }
1369
- await this.mailchannels.put(`/tx/v1/sub-account/${handle}/limit`, {
1370
- body: limit,
1273
+ await this.mailchannels.put(`/tx/v1/sub-account/${encodeURIComponent(handle)}/limit`, {
1274
+ body: options,
1371
1275
  onResponseError: async ({ response }) => {
1372
1276
  error = getStatusError(response, {
1373
1277
  [400]: "Bad Request.",
@@ -1382,7 +1286,7 @@ var SubAccounts = class SubAccounts {
1382
1286
  error
1383
1287
  };
1384
1288
  }
1385
- async deleteLimit(handle) {
1289
+ async delete(handle) {
1386
1290
  let error = null;
1387
1291
  if (!handle) {
1388
1292
  error = createValidationError("No handle provided.");
@@ -1391,7 +1295,7 @@ var SubAccounts = class SubAccounts {
1391
1295
  error
1392
1296
  };
1393
1297
  }
1394
- await this.mailchannels.delete(`/tx/v1/sub-account/${handle}/limit`, { onResponseError: async ({ response }) => {
1298
+ await this.mailchannels.delete(`/tx/v1/sub-account/${encodeURIComponent(handle)}/limit`, { onResponseError: async ({ response }) => {
1395
1299
  error = getStatusError(response, { [404]: `Sub-account with handle '${handle}' not found.` });
1396
1300
  } }).catch((e) => {
1397
1301
  error ||= getResultError(e, "Failed to delete sub-account limit.");
@@ -1401,6 +1305,158 @@ var SubAccounts = class SubAccounts {
1401
1305
  error
1402
1306
  };
1403
1307
  }
1308
+ };
1309
+ var SubAccounts = class SubAccounts {
1310
+ mailchannels;
1311
+ static COMPANY_PATTERN = /^.{3,128}$/;
1312
+ static HANDLE_PATTERN = /^[a-z0-9]{3,128}$/;
1313
+ apiKeys;
1314
+ smtpPasswords;
1315
+ limits;
1316
+ constructor(mailchannels) {
1317
+ this.mailchannels = mailchannels;
1318
+ this.apiKeys = new SubAccountsApiKeys(mailchannels);
1319
+ this.smtpPasswords = new SubAccountsSmtpPasswords(mailchannels);
1320
+ this.limits = new SubAccountsLimits(mailchannels);
1321
+ }
1322
+ async create(companyName, handle) {
1323
+ let error = null;
1324
+ if (!SubAccounts.COMPANY_PATTERN.test(companyName)) {
1325
+ error = createValidationError("Invalid company name. Company name must be between 3 and 128 characters.");
1326
+ return {
1327
+ data: null,
1328
+ error
1329
+ };
1330
+ }
1331
+ if (handle) {
1332
+ if (!SubAccounts.HANDLE_PATTERN.test(handle)) {
1333
+ error = createValidationError("Invalid handle. Sub-account handle must be between 3 and 128 characters and contain only lowercase letters and numbers.");
1334
+ return {
1335
+ data: null,
1336
+ error
1337
+ };
1338
+ }
1339
+ }
1340
+ const response = await this.mailchannels.post("/tx/v1/sub-account", {
1341
+ body: {
1342
+ company_name: companyName,
1343
+ handle
1344
+ },
1345
+ onResponseError: async ({ response }) => {
1346
+ error = getStatusError(response, {
1347
+ [403]: "The parent account does not have permission to create sub-accounts.",
1348
+ [409]: `Sub-account with handle '${handle}' already exists.`
1349
+ });
1350
+ }
1351
+ }).catch((e) => {
1352
+ error ||= getResultError(e, "Failed to create sub-account.");
1353
+ return null;
1354
+ });
1355
+ if (!response) return {
1356
+ data: null,
1357
+ error
1358
+ };
1359
+ return {
1360
+ data: clean({
1361
+ companyName: response.company_name,
1362
+ enabled: response.enabled,
1363
+ handle: response.handle
1364
+ }),
1365
+ error: null
1366
+ };
1367
+ }
1368
+ async list(options) {
1369
+ let error = null;
1370
+ error = validatePagination({
1371
+ ...options,
1372
+ max: 1e3
1373
+ });
1374
+ if (error) return {
1375
+ data: null,
1376
+ error
1377
+ };
1378
+ const response = await this.mailchannels.get("/tx/v1/sub-account", {
1379
+ query: options,
1380
+ onResponseError: async ({ response }) => {
1381
+ error = getStatusError(response);
1382
+ }
1383
+ }).catch((e) => {
1384
+ error ||= getResultError(e, "Failed to fetch sub-accounts.");
1385
+ return null;
1386
+ });
1387
+ if (!response) return {
1388
+ data: null,
1389
+ error
1390
+ };
1391
+ return {
1392
+ data: clean(response.map((account) => ({
1393
+ companyName: account.company_name,
1394
+ enabled: account.enabled,
1395
+ handle: account.handle
1396
+ }))),
1397
+ error: null
1398
+ };
1399
+ }
1400
+ async delete(handle) {
1401
+ let error = null;
1402
+ if (!handle) {
1403
+ error = createValidationError("No handle provided.");
1404
+ return {
1405
+ success: false,
1406
+ error
1407
+ };
1408
+ }
1409
+ await this.mailchannels.delete(`/tx/v1/sub-account/${encodeURIComponent(handle)}`, { onResponseError: async ({ response }) => {
1410
+ error = getStatusError(response);
1411
+ } }).catch((e) => {
1412
+ error ||= getResultError(e, "Failed to delete sub-account.");
1413
+ });
1414
+ return {
1415
+ success: !error,
1416
+ error
1417
+ };
1418
+ }
1419
+ async suspend(handle) {
1420
+ let error = null;
1421
+ if (!handle) {
1422
+ error = createValidationError("No handle provided.");
1423
+ return {
1424
+ success: false,
1425
+ error
1426
+ };
1427
+ }
1428
+ await this.mailchannels.post(`/tx/v1/sub-account/${encodeURIComponent(handle)}/suspend`, { onResponseError: async ({ response }) => {
1429
+ error = getStatusError(response, { [404]: `The specified sub-account '${handle}' does not exist.` });
1430
+ } }).catch((e) => {
1431
+ error ||= getResultError(e, "Failed to suspend sub-account.");
1432
+ });
1433
+ return {
1434
+ success: !error,
1435
+ error
1436
+ };
1437
+ }
1438
+ async activate(handle) {
1439
+ let error = null;
1440
+ if (!handle) {
1441
+ error = createValidationError("No handle provided.");
1442
+ return {
1443
+ success: false,
1444
+ error
1445
+ };
1446
+ }
1447
+ await this.mailchannels.post(`/tx/v1/sub-account/${encodeURIComponent(handle)}/activate`, { onResponseError: async ({ response }) => {
1448
+ error = getStatusError(response, {
1449
+ [403]: "The parent account does not have permission to activate the sub-account.",
1450
+ [404]: `The specified sub-account '${handle}' does not exist.`
1451
+ });
1452
+ } }).catch((e) => {
1453
+ error ||= getResultError(e, "Failed to activate sub-account.");
1454
+ });
1455
+ return {
1456
+ success: !error,
1457
+ error
1458
+ };
1459
+ }
1404
1460
  async getUsage(handle) {
1405
1461
  let error = null;
1406
1462
  if (!handle) {
@@ -1410,7 +1466,7 @@ var SubAccounts = class SubAccounts {
1410
1466
  error
1411
1467
  };
1412
1468
  }
1413
- const response = await this.mailchannels.get(`/tx/v1/sub-account/${handle}/usage`, { onResponseError: async ({ response }) => {
1469
+ const response = await this.mailchannels.get(`/tx/v1/sub-account/${encodeURIComponent(handle)}/usage`, { onResponseError: async ({ response }) => {
1414
1470
  error = getStatusError(response, { [404]: `Sub-account with handle '${handle}' not found.` });
1415
1471
  } }).catch((e) => {
1416
1472
  error ||= getResultError(e, "Failed to fetch sub-account usage.");
@@ -1429,6 +1485,33 @@ var SubAccounts = class SubAccounts {
1429
1485
  error: null
1430
1486
  };
1431
1487
  }
1488
+ createApiKey(...args) {
1489
+ return this.apiKeys.create(...args);
1490
+ }
1491
+ listApiKeys(...args) {
1492
+ return this.apiKeys.list(...args);
1493
+ }
1494
+ deleteApiKey(...args) {
1495
+ return this.apiKeys.delete(...args);
1496
+ }
1497
+ createSmtpPassword(...args) {
1498
+ return this.smtpPasswords.create(...args);
1499
+ }
1500
+ listSmtpPasswords(...args) {
1501
+ return this.smtpPasswords.list(...args);
1502
+ }
1503
+ deleteSmtpPassword(...args) {
1504
+ return this.smtpPasswords.delete(...args);
1505
+ }
1506
+ setLimit(...args) {
1507
+ return this.limits.set(...args);
1508
+ }
1509
+ getLimit(...args) {
1510
+ return this.limits.get(...args);
1511
+ }
1512
+ deleteLimit(...args) {
1513
+ return this.limits.delete(...args);
1514
+ }
1432
1515
  };
1433
1516
  const mapBucket = (bucket) => {
1434
1517
  return {
@@ -1443,10 +1526,18 @@ var Metrics = class {
1443
1526
  }
1444
1527
  async engagement(options) {
1445
1528
  let error = null;
1529
+ const { dates, error: dateError } = parseDateInputs({
1530
+ startTime: options?.startTime,
1531
+ endTime: options?.endTime
1532
+ });
1533
+ if (!dates || dateError) return {
1534
+ data: null,
1535
+ error: dateError
1536
+ };
1446
1537
  const response = await this.mailchannels.get("/tx/v1/metrics/engagement", {
1447
1538
  query: {
1448
- start_time: options?.startTime,
1449
- end_time: options?.endTime,
1539
+ start_time: dates.startTime,
1540
+ end_time: dates.endTime,
1450
1541
  campaign_id: options?.campaignId,
1451
1542
  interval: options?.interval
1452
1543
  },
@@ -1481,10 +1572,18 @@ var Metrics = class {
1481
1572
  }
1482
1573
  async performance(options) {
1483
1574
  let error = null;
1575
+ const { dates, error: dateError } = parseDateInputs({
1576
+ startTime: options?.startTime,
1577
+ endTime: options?.endTime
1578
+ });
1579
+ if (!dates || dateError) return {
1580
+ data: null,
1581
+ error: dateError
1582
+ };
1484
1583
  const response = await this.mailchannels.get("/tx/v1/metrics/performance", {
1485
1584
  query: {
1486
- start_time: options?.startTime,
1487
- end_time: options?.endTime,
1585
+ start_time: dates.startTime,
1586
+ end_time: dates.endTime,
1488
1587
  campaign_id: options?.campaignId,
1489
1588
  interval: options?.interval
1490
1589
  },
@@ -1517,10 +1616,18 @@ var Metrics = class {
1517
1616
  }
1518
1617
  async recipientBehaviour(options) {
1519
1618
  let error = null;
1619
+ const { dates, error: dateError } = parseDateInputs({
1620
+ startTime: options?.startTime,
1621
+ endTime: options?.endTime
1622
+ });
1623
+ if (!dates || dateError) return {
1624
+ data: null,
1625
+ error: dateError
1626
+ };
1520
1627
  const response = await this.mailchannels.get("/tx/v1/metrics/recipient-behaviour", {
1521
1628
  query: {
1522
- start_time: options?.startTime,
1523
- end_time: options?.endTime,
1629
+ start_time: dates.startTime,
1630
+ end_time: dates.endTime,
1524
1631
  campaign_id: options?.campaignId,
1525
1632
  interval: options?.interval
1526
1633
  },
@@ -1551,10 +1658,18 @@ var Metrics = class {
1551
1658
  }
1552
1659
  async volume(options) {
1553
1660
  let error = null;
1661
+ const { dates, error: dateError } = parseDateInputs({
1662
+ startTime: options?.startTime,
1663
+ endTime: options?.endTime
1664
+ });
1665
+ if (!dates || dateError) return {
1666
+ data: null,
1667
+ error: dateError
1668
+ };
1554
1669
  const response = await this.mailchannels.get("/tx/v1/metrics/volume", {
1555
1670
  query: {
1556
- start_time: options?.startTime,
1557
- end_time: options?.endTime,
1671
+ start_time: dates.startTime,
1672
+ end_time: dates.endTime,
1558
1673
  campaign_id: options?.campaignId,
1559
1674
  interval: options?.interval
1560
1675
  },
@@ -1608,6 +1723,14 @@ var Metrics = class {
1608
1723
  }
1609
1724
  async senders(type, options) {
1610
1725
  let error = null;
1726
+ const { dates, error: dateError } = parseDateInputs({
1727
+ startTime: options?.startTime,
1728
+ endTime: options?.endTime
1729
+ });
1730
+ if (!dates || dateError) return {
1731
+ data: null,
1732
+ error: dateError
1733
+ };
1611
1734
  error = validatePagination({
1612
1735
  ...options,
1613
1736
  max: 1e3
@@ -1616,10 +1739,10 @@ var Metrics = class {
1616
1739
  data: null,
1617
1740
  error
1618
1741
  };
1619
- const response = await this.mailchannels.get(`/tx/v1/metrics/senders/${type}`, {
1742
+ const response = await this.mailchannels.get(`/tx/v1/metrics/senders/${encodeURIComponent(type)}`, {
1620
1743
  query: {
1621
- start_time: options?.startTime,
1622
- end_time: options?.endTime,
1744
+ start_time: dates.startTime,
1745
+ end_time: dates.endTime,
1623
1746
  limit: options?.limit,
1624
1747
  offset: options?.offset,
1625
1748
  sort_order: options?.sortOrder
@@ -1690,7 +1813,7 @@ var Suppressions = class {
1690
1813
  }
1691
1814
  async delete(recipient, source) {
1692
1815
  let error = null;
1693
- await this.mailchannels.delete(`/tx/v1/suppression-list/recipients/${recipient}`, {
1816
+ await this.mailchannels.delete(`/tx/v1/suppression-list/recipients/${encodeURIComponent(recipient)}`, {
1694
1817
  query: { source },
1695
1818
  onResponseError: async ({ response }) => {
1696
1819
  error = getStatusError(response, { [400]: "Bad Request." });
@@ -1712,6 +1835,14 @@ var Suppressions = class {
1712
1835
  error
1713
1836
  };
1714
1837
  }
1838
+ const { dates, error: dateError } = parseDateInputs({
1839
+ createdBefore: options?.createdBefore,
1840
+ createdAfter: options?.createdAfter
1841
+ });
1842
+ if (!dates || dateError) return {
1843
+ data: null,
1844
+ error: dateError
1845
+ };
1715
1846
  error = validatePagination({
1716
1847
  ...options,
1717
1848
  max: 1e3
@@ -1723,8 +1854,8 @@ var Suppressions = class {
1723
1854
  const payload = {
1724
1855
  recipient: options?.recipient,
1725
1856
  source: options?.source,
1726
- created_before: options?.createdBefore,
1727
- created_after: options?.createdAfter,
1857
+ created_before: dates.createdBefore,
1858
+ created_after: dates.createdAfter,
1728
1859
  limit: options?.limit,
1729
1860
  offset: options?.offset
1730
1861
  };