import {
  Route53Client
} from "./chunk-32e7ya18.js";
import {
  S3Client
} from "./chunk-wj3s95p9.js";
import {
  AWSClient
} from "./chunk-zqtpg06c.js";
import {
  __require
} from "./chunk-v0bahtg2.js";

// src/aws/iam.ts
function buildQueryParams(action, params) {
  const queryParams = [`Action=${action}`, "Version=2010-05-08"];
  for (const [key, value] of Object.entries(params)) {
    if (value === undefined || value === null)
      continue;
    if (Array.isArray(value)) {
      value.forEach((item, index) => {
        if (typeof item === "object" && item !== null) {
          for (const [subKey, subValue] of Object.entries(item)) {
            queryParams.push(`${key}.member.${index + 1}.${subKey}=${encodeURIComponent(String(subValue))}`);
          }
        } else {
          queryParams.push(`${key}.member.${index + 1}=${encodeURIComponent(String(item))}`);
        }
      });
    } else if (typeof value === "object") {
      for (const [subKey, subValue] of Object.entries(value)) {
        if (subValue !== undefined && subValue !== null) {
          queryParams.push(`${key}.${subKey}=${encodeURIComponent(String(subValue))}`);
        }
      }
    } else {
      queryParams.push(`${key}=${encodeURIComponent(String(value))}`);
    }
  }
  return queryParams.join("&");
}
function parseXmlValue(xml, tag) {
  const regex = new RegExp(`<${tag}>([^<]*)</${tag}>`);
  const match = xml.match(regex);
  return match ? match[1] : undefined;
}
function parseXmlArray(xml, containerTag, itemTag) {
  const containerRegex = new RegExp(`<${containerTag}>([\\s\\S]*?)</${containerTag}>`);
  const containerMatch = xml.match(containerRegex);
  if (!containerMatch)
    return [];
  const items = [];
  const itemRegex = new RegExp(`<${itemTag}>([\\s\\S]*?)</${itemTag}>`, "g");
  let match;
  while ((match = itemRegex.exec(containerMatch[1])) !== null) {
    items.push(match[1]);
  }
  return items;
}

class IAMClient {
  client;
  region;
  constructor(region = "us-east-1", profile) {
    this.client = new AWSClient(undefined, { profile });
    this.region = region;
  }
  async request(action, params = {}) {
    const body = buildQueryParams(action, params);
    const response = await this.client.request({
      service: "iam",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body
    });
    return response;
  }
  async createUser(params) {
    const response = await this.request("CreateUser", params);
    return this.parseUser(response);
  }
  async getUser(params = {}) {
    const response = await this.request("GetUser", params);
    return this.parseUser(response);
  }
  async listUsers(params = {}) {
    const response = await this.request("ListUsers", params);
    const users = this.parseUsers(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { Users: users, IsTruncated: isTruncated, Marker: marker };
  }
  async updateUser(params) {
    await this.request("UpdateUser", params);
  }
  async deleteUser(params) {
    await this.request("DeleteUser", params);
  }
  parseUser(xml) {
    return {
      UserName: parseXmlValue(xml, "UserName") || "",
      UserId: parseXmlValue(xml, "UserId") || "",
      Arn: parseXmlValue(xml, "Arn") || "",
      Path: parseXmlValue(xml, "Path"),
      CreateDate: parseXmlValue(xml, "CreateDate"),
      PasswordLastUsed: parseXmlValue(xml, "PasswordLastUsed")
    };
  }
  parseUsers(xml) {
    const memberXmls = parseXmlArray(xml, "Users", "member");
    return memberXmls.map((memberXml) => ({
      UserName: parseXmlValue(memberXml, "UserName") || "",
      UserId: parseXmlValue(memberXml, "UserId") || "",
      Arn: parseXmlValue(memberXml, "Arn") || "",
      Path: parseXmlValue(memberXml, "Path"),
      CreateDate: parseXmlValue(memberXml, "CreateDate"),
      PasswordLastUsed: parseXmlValue(memberXml, "PasswordLastUsed")
    }));
  }
  async createGroup(params) {
    const response = await this.request("CreateGroup", params);
    return this.parseGroup(response);
  }
  async getGroup(params) {
    const response = await this.request("GetGroup", params);
    const group = this.parseGroup(response);
    const users = this.parseUsers(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { Group: group, Users: users, IsTruncated: isTruncated, Marker: marker };
  }
  async listGroups(params = {}) {
    const response = await this.request("ListGroups", params);
    const groups = this.parseGroups(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { Groups: groups, IsTruncated: isTruncated, Marker: marker };
  }
  async updateGroup(params) {
    await this.request("UpdateGroup", params);
  }
  async deleteGroup(params) {
    await this.request("DeleteGroup", params);
  }
  async addUserToGroup(params) {
    await this.request("AddUserToGroup", params);
  }
  async removeUserFromGroup(params) {
    await this.request("RemoveUserFromGroup", params);
  }
  async listGroupsForUser(params) {
    const response = await this.request("ListGroupsForUser", params);
    const groups = this.parseGroups(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { Groups: groups, IsTruncated: isTruncated, Marker: marker };
  }
  parseGroup(xml) {
    return {
      GroupName: parseXmlValue(xml, "GroupName") || "",
      GroupId: parseXmlValue(xml, "GroupId") || "",
      Arn: parseXmlValue(xml, "Arn") || "",
      Path: parseXmlValue(xml, "Path"),
      CreateDate: parseXmlValue(xml, "CreateDate")
    };
  }
  parseGroups(xml) {
    const memberXmls = parseXmlArray(xml, "Groups", "member");
    return memberXmls.map((memberXml) => ({
      GroupName: parseXmlValue(memberXml, "GroupName") || "",
      GroupId: parseXmlValue(memberXml, "GroupId") || "",
      Arn: parseXmlValue(memberXml, "Arn") || "",
      Path: parseXmlValue(memberXml, "Path"),
      CreateDate: parseXmlValue(memberXml, "CreateDate")
    }));
  }
  async createRole(params) {
    const response = await this.request("CreateRole", params);
    return this.parseRole(response);
  }
  async getRole(params) {
    const response = await this.request("GetRole", params);
    return this.parseRole(response);
  }
  async listRoles(params = {}) {
    const response = await this.request("ListRoles", params);
    const roles = this.parseRoles(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { Roles: roles, IsTruncated: isTruncated, Marker: marker };
  }
  async updateRole(params) {
    await this.request("UpdateRole", params);
  }
  async updateRoleDescription(params) {
    const response = await this.request("UpdateRoleDescription", params);
    return this.parseRole(response);
  }
  async updateAssumeRolePolicy(params) {
    await this.request("UpdateAssumeRolePolicy", params);
  }
  async deleteRole(params) {
    await this.request("DeleteRole", params);
  }
  async tagRole(params) {
    await this.request("TagRole", params);
  }
  async untagRole(params) {
    await this.request("UntagRole", params);
  }
  async listRoleTags(params) {
    const response = await this.request("ListRoleTags", params);
    const tags = this.parseTags(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { Tags: tags, IsTruncated: isTruncated, Marker: marker };
  }
  parseRole(xml) {
    return {
      RoleName: parseXmlValue(xml, "RoleName") || "",
      RoleId: parseXmlValue(xml, "RoleId") || "",
      Arn: parseXmlValue(xml, "Arn") || "",
      Path: parseXmlValue(xml, "Path"),
      CreateDate: parseXmlValue(xml, "CreateDate"),
      AssumeRolePolicyDocument: parseXmlValue(xml, "AssumeRolePolicyDocument"),
      Description: parseXmlValue(xml, "Description"),
      MaxSessionDuration: parseXmlValue(xml, "MaxSessionDuration") ? Number.parseInt(parseXmlValue(xml, "MaxSessionDuration"), 10) : undefined
    };
  }
  parseRoles(xml) {
    const memberXmls = parseXmlArray(xml, "Roles", "member");
    return memberXmls.map((memberXml) => ({
      RoleName: parseXmlValue(memberXml, "RoleName") || "",
      RoleId: parseXmlValue(memberXml, "RoleId") || "",
      Arn: parseXmlValue(memberXml, "Arn") || "",
      Path: parseXmlValue(memberXml, "Path"),
      CreateDate: parseXmlValue(memberXml, "CreateDate"),
      AssumeRolePolicyDocument: parseXmlValue(memberXml, "AssumeRolePolicyDocument"),
      Description: parseXmlValue(memberXml, "Description"),
      MaxSessionDuration: parseXmlValue(memberXml, "MaxSessionDuration") ? Number.parseInt(parseXmlValue(memberXml, "MaxSessionDuration"), 10) : undefined
    }));
  }
  parseTags(xml) {
    const memberXmls = parseXmlArray(xml, "Tags", "member");
    return memberXmls.map((memberXml) => ({
      Key: parseXmlValue(memberXml, "Key") || "",
      Value: parseXmlValue(memberXml, "Value") || ""
    }));
  }
  async createPolicy(params) {
    const response = await this.request("CreatePolicy", params);
    return this.parsePolicy(response);
  }
  async getPolicy(params) {
    const response = await this.request("GetPolicy", params);
    return this.parsePolicy(response);
  }
  async getPolicyVersion(params) {
    const response = await this.request("GetPolicyVersion", params);
    return {
      VersionId: parseXmlValue(response, "VersionId") || "",
      IsDefaultVersion: parseXmlValue(response, "IsDefaultVersion") === "true",
      CreateDate: parseXmlValue(response, "CreateDate"),
      Document: parseXmlValue(response, "Document")
    };
  }
  async listPolicies(params = {}) {
    const response = await this.request("ListPolicies", params);
    const policies = this.parsePolicies(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { Policies: policies, IsTruncated: isTruncated, Marker: marker };
  }
  async listPolicyVersions(params) {
    const response = await this.request("ListPolicyVersions", params);
    const versions = this.parsePolicyVersions(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { Versions: versions, IsTruncated: isTruncated, Marker: marker };
  }
  async createPolicyVersion(params) {
    const response = await this.request("CreatePolicyVersion", params);
    return {
      VersionId: parseXmlValue(response, "VersionId") || "",
      IsDefaultVersion: parseXmlValue(response, "IsDefaultVersion") === "true",
      CreateDate: parseXmlValue(response, "CreateDate")
    };
  }
  async deletePolicyVersion(params) {
    await this.request("DeletePolicyVersion", params);
  }
  async setDefaultPolicyVersion(params) {
    await this.request("SetDefaultPolicyVersion", params);
  }
  async deletePolicy(params) {
    await this.request("DeletePolicy", params);
  }
  async attachUserPolicy(params) {
    await this.request("AttachUserPolicy", params);
  }
  async detachUserPolicy(params) {
    await this.request("DetachUserPolicy", params);
  }
  async attachGroupPolicy(params) {
    await this.request("AttachGroupPolicy", params);
  }
  async detachGroupPolicy(params) {
    await this.request("DetachGroupPolicy", params);
  }
  async attachRolePolicy(params) {
    await this.request("AttachRolePolicy", params);
  }
  async detachRolePolicy(params) {
    await this.request("DetachRolePolicy", params);
  }
  async listAttachedUserPolicies(params) {
    const response = await this.request("ListAttachedUserPolicies", params);
    const policies = this.parseAttachedPolicies(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { AttachedPolicies: policies, IsTruncated: isTruncated, Marker: marker };
  }
  async listAttachedGroupPolicies(params) {
    const response = await this.request("ListAttachedGroupPolicies", params);
    const policies = this.parseAttachedPolicies(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { AttachedPolicies: policies, IsTruncated: isTruncated, Marker: marker };
  }
  async listAttachedRolePolicies(params) {
    const response = await this.request("ListAttachedRolePolicies", params);
    const policies = this.parseAttachedPolicies(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { AttachedPolicies: policies, IsTruncated: isTruncated, Marker: marker };
  }
  parsePolicy(xml) {
    return {
      PolicyName: parseXmlValue(xml, "PolicyName") || "",
      PolicyId: parseXmlValue(xml, "PolicyId") || "",
      Arn: parseXmlValue(xml, "Arn") || "",
      Path: parseXmlValue(xml, "Path"),
      DefaultVersionId: parseXmlValue(xml, "DefaultVersionId"),
      AttachmentCount: parseXmlValue(xml, "AttachmentCount") ? Number.parseInt(parseXmlValue(xml, "AttachmentCount"), 10) : undefined,
      PermissionsBoundaryUsageCount: parseXmlValue(xml, "PermissionsBoundaryUsageCount") ? Number.parseInt(parseXmlValue(xml, "PermissionsBoundaryUsageCount"), 10) : undefined,
      IsAttachable: parseXmlValue(xml, "IsAttachable") === "true",
      Description: parseXmlValue(xml, "Description"),
      CreateDate: parseXmlValue(xml, "CreateDate"),
      UpdateDate: parseXmlValue(xml, "UpdateDate")
    };
  }
  parsePolicies(xml) {
    const memberXmls = parseXmlArray(xml, "Policies", "member");
    return memberXmls.map((memberXml) => ({
      PolicyName: parseXmlValue(memberXml, "PolicyName") || "",
      PolicyId: parseXmlValue(memberXml, "PolicyId") || "",
      Arn: parseXmlValue(memberXml, "Arn") || "",
      Path: parseXmlValue(memberXml, "Path"),
      DefaultVersionId: parseXmlValue(memberXml, "DefaultVersionId"),
      AttachmentCount: parseXmlValue(memberXml, "AttachmentCount") ? Number.parseInt(parseXmlValue(memberXml, "AttachmentCount"), 10) : undefined,
      PermissionsBoundaryUsageCount: parseXmlValue(memberXml, "PermissionsBoundaryUsageCount") ? Number.parseInt(parseXmlValue(memberXml, "PermissionsBoundaryUsageCount"), 10) : undefined,
      IsAttachable: parseXmlValue(memberXml, "IsAttachable") === "true",
      Description: parseXmlValue(memberXml, "Description"),
      CreateDate: parseXmlValue(memberXml, "CreateDate"),
      UpdateDate: parseXmlValue(memberXml, "UpdateDate")
    }));
  }
  parsePolicyVersions(xml) {
    const memberXmls = parseXmlArray(xml, "Versions", "member");
    return memberXmls.map((memberXml) => ({
      VersionId: parseXmlValue(memberXml, "VersionId") || "",
      IsDefaultVersion: parseXmlValue(memberXml, "IsDefaultVersion") === "true",
      CreateDate: parseXmlValue(memberXml, "CreateDate")
    }));
  }
  parseAttachedPolicies(xml) {
    const memberXmls = parseXmlArray(xml, "AttachedPolicies", "member");
    return memberXmls.map((memberXml) => ({
      PolicyName: parseXmlValue(memberXml, "PolicyName") || "",
      PolicyArn: parseXmlValue(memberXml, "PolicyArn") || ""
    }));
  }
  async putUserPolicy(params) {
    await this.request("PutUserPolicy", params);
  }
  async getUserPolicy(params) {
    const response = await this.request("GetUserPolicy", params);
    return {
      UserName: parseXmlValue(response, "UserName") || "",
      PolicyName: parseXmlValue(response, "PolicyName") || "",
      PolicyDocument: decodeURIComponent(parseXmlValue(response, "PolicyDocument") || "")
    };
  }
  async deleteUserPolicy(params) {
    await this.request("DeleteUserPolicy", params);
  }
  async listUserPolicies(params) {
    const response = await this.request("ListUserPolicies", params);
    const policyNames = parseXmlArray(response, "PolicyNames", "member");
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { PolicyNames: policyNames, IsTruncated: isTruncated, Marker: marker };
  }
  async putGroupPolicy(params) {
    await this.request("PutGroupPolicy", params);
  }
  async getGroupPolicy(params) {
    const response = await this.request("GetGroupPolicy", params);
    return {
      GroupName: parseXmlValue(response, "GroupName") || "",
      PolicyName: parseXmlValue(response, "PolicyName") || "",
      PolicyDocument: decodeURIComponent(parseXmlValue(response, "PolicyDocument") || "")
    };
  }
  async deleteGroupPolicy(params) {
    await this.request("DeleteGroupPolicy", params);
  }
  async listGroupPolicies(params) {
    const response = await this.request("ListGroupPolicies", params);
    const policyNames = parseXmlArray(response, "PolicyNames", "member");
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { PolicyNames: policyNames, IsTruncated: isTruncated, Marker: marker };
  }
  async putRolePolicy(params) {
    await this.request("PutRolePolicy", params);
  }
  async getRolePolicy(params) {
    const response = await this.request("GetRolePolicy", params);
    return {
      RoleName: parseXmlValue(response, "RoleName") || "",
      PolicyName: parseXmlValue(response, "PolicyName") || "",
      PolicyDocument: decodeURIComponent(parseXmlValue(response, "PolicyDocument") || "")
    };
  }
  async deleteRolePolicy(params) {
    await this.request("DeleteRolePolicy", params);
  }
  async listRolePolicies(params) {
    const response = await this.request("ListRolePolicies", params);
    const policyNames = parseXmlArray(response, "PolicyNames", "member");
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { PolicyNames: policyNames, IsTruncated: isTruncated, Marker: marker };
  }
  async createAccessKey(params = {}) {
    const response = await this.request("CreateAccessKey", params);
    if (typeof response === "object") {
      const accessKey = response?.CreateAccessKeyResult?.AccessKey || response?.AccessKey;
      if (accessKey) {
        return {
          AccessKey: {
            UserName: accessKey.UserName || "",
            AccessKeyId: accessKey.AccessKeyId || "",
            Status: accessKey.Status || "Active",
            SecretAccessKey: accessKey.SecretAccessKey || "",
            CreateDate: accessKey.CreateDate
          }
        };
      }
    }
    return {
      AccessKey: {
        UserName: parseXmlValue(response, "UserName") || "",
        AccessKeyId: parseXmlValue(response, "AccessKeyId") || "",
        Status: parseXmlValue(response, "Status") || "Active",
        SecretAccessKey: parseXmlValue(response, "SecretAccessKey") || "",
        CreateDate: parseXmlValue(response, "CreateDate")
      }
    };
  }
  async listAccessKeys(params = {}) {
    const response = await this.request("ListAccessKeys", params);
    const keys = this.parseAccessKeys(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { AccessKeyMetadata: keys, IsTruncated: isTruncated, Marker: marker };
  }
  async updateAccessKey(params) {
    await this.request("UpdateAccessKey", params);
  }
  async deleteAccessKey(params) {
    await this.request("DeleteAccessKey", params);
  }
  async getAccessKeyLastUsed(params) {
    const response = await this.request("GetAccessKeyLastUsed", params);
    return {
      UserName: parseXmlValue(response, "UserName") || "",
      AccessKeyLastUsed: {
        LastUsedDate: parseXmlValue(response, "LastUsedDate"),
        ServiceName: parseXmlValue(response, "ServiceName"),
        Region: parseXmlValue(response, "Region")
      }
    };
  }
  parseAccessKeys(xml) {
    const memberXmls = parseXmlArray(xml, "AccessKeyMetadata", "member");
    return memberXmls.map((memberXml) => ({
      UserName: parseXmlValue(memberXml, "UserName"),
      AccessKeyId: parseXmlValue(memberXml, "AccessKeyId") || "",
      Status: parseXmlValue(memberXml, "Status") || "Active",
      CreateDate: parseXmlValue(memberXml, "CreateDate")
    }));
  }
  async createInstanceProfile(params) {
    const response = await this.request("CreateInstanceProfile", params);
    return this.parseInstanceProfile(response);
  }
  async getInstanceProfile(params) {
    const response = await this.request("GetInstanceProfile", params);
    return this.parseInstanceProfile(response);
  }
  async listInstanceProfiles(params = {}) {
    const response = await this.request("ListInstanceProfiles", params);
    const profiles = this.parseInstanceProfiles(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { InstanceProfiles: profiles, IsTruncated: isTruncated, Marker: marker };
  }
  async listInstanceProfilesForRole(params) {
    const response = await this.request("ListInstanceProfilesForRole", params);
    const profiles = this.parseInstanceProfiles(response);
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { InstanceProfiles: profiles, IsTruncated: isTruncated, Marker: marker };
  }
  async addRoleToInstanceProfile(params) {
    await this.request("AddRoleToInstanceProfile", params);
  }
  async removeRoleFromInstanceProfile(params) {
    await this.request("RemoveRoleFromInstanceProfile", params);
  }
  async deleteInstanceProfile(params) {
    await this.request("DeleteInstanceProfile", params);
  }
  parseInstanceProfile(xml) {
    return {
      InstanceProfileName: parseXmlValue(xml, "InstanceProfileName") || "",
      InstanceProfileId: parseXmlValue(xml, "InstanceProfileId") || "",
      Arn: parseXmlValue(xml, "Arn") || "",
      Path: parseXmlValue(xml, "Path"),
      CreateDate: parseXmlValue(xml, "CreateDate")
    };
  }
  parseInstanceProfiles(xml) {
    const memberXmls = parseXmlArray(xml, "InstanceProfiles", "member");
    return memberXmls.map((memberXml) => ({
      InstanceProfileName: parseXmlValue(memberXml, "InstanceProfileName") || "",
      InstanceProfileId: parseXmlValue(memberXml, "InstanceProfileId") || "",
      Arn: parseXmlValue(memberXml, "Arn") || "",
      Path: parseXmlValue(memberXml, "Path"),
      CreateDate: parseXmlValue(memberXml, "CreateDate")
    }));
  }
  async getAccountPasswordPolicy() {
    const response = await this.request("GetAccountPasswordPolicy");
    return {
      MinimumPasswordLength: parseXmlValue(response, "MinimumPasswordLength") ? Number.parseInt(parseXmlValue(response, "MinimumPasswordLength"), 10) : undefined,
      RequireSymbols: parseXmlValue(response, "RequireSymbols") === "true",
      RequireNumbers: parseXmlValue(response, "RequireNumbers") === "true",
      RequireUppercaseCharacters: parseXmlValue(response, "RequireUppercaseCharacters") === "true",
      RequireLowercaseCharacters: parseXmlValue(response, "RequireLowercaseCharacters") === "true",
      AllowUsersToChangePassword: parseXmlValue(response, "AllowUsersToChangePassword") === "true",
      ExpirePasswords: parseXmlValue(response, "ExpirePasswords") === "true",
      MaxPasswordAge: parseXmlValue(response, "MaxPasswordAge") ? Number.parseInt(parseXmlValue(response, "MaxPasswordAge"), 10) : undefined,
      PasswordReusePrevention: parseXmlValue(response, "PasswordReusePrevention") ? Number.parseInt(parseXmlValue(response, "PasswordReusePrevention"), 10) : undefined,
      HardExpiry: parseXmlValue(response, "HardExpiry") === "true"
    };
  }
  async updateAccountPasswordPolicy(params) {
    await this.request("UpdateAccountPasswordPolicy", params);
  }
  async deleteAccountPasswordPolicy() {
    await this.request("DeleteAccountPasswordPolicy");
  }
  async getAccountSummary() {
    const response = await this.request("GetAccountSummary");
    const summary = {};
    const entries = parseXmlArray(response, "SummaryMap", "entry");
    for (const entry of entries) {
      const key = parseXmlValue(entry, "key");
      const value = parseXmlValue(entry, "value");
      if (key && value) {
        summary[key] = Number.parseInt(value, 10);
      }
    }
    return summary;
  }
  async listAccountAliases() {
    const response = await this.request("ListAccountAliases");
    const aliases = parseXmlArray(response, "AccountAliases", "member");
    const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
    const marker = parseXmlValue(response, "Marker");
    return { AccountAliases: aliases, IsTruncated: isTruncated, Marker: marker };
  }
  async createAccountAlias(params) {
    await this.request("CreateAccountAlias", params);
  }
  async deleteAccountAlias(params) {
    await this.request("DeleteAccountAlias", params);
  }
  async simulatePrincipalPolicy(params) {
    const response = await this.request("SimulatePrincipalPolicy", params);
    return this.parseSimulationResults(response);
  }
  parseSimulationResults(xml) {
    const resultXmls = parseXmlArray(xml, "EvaluationResults", "member");
    const evaluationResults = resultXmls.map((resultXml) => {
      const matchedStatementXmls = parseXmlArray(resultXml, "MatchedStatements", "member");
      const matchedStatements = matchedStatementXmls.map((stmtXml) => ({
        SourcePolicyId: parseXmlValue(stmtXml, "SourcePolicyId"),
        SourcePolicyType: parseXmlValue(stmtXml, "SourcePolicyType")
      }));
      return {
        EvalActionName: parseXmlValue(resultXml, "EvalActionName") || "",
        EvalResourceName: parseXmlValue(resultXml, "EvalResourceName"),
        EvalDecision: parseXmlValue(resultXml, "EvalDecision") || "",
        MatchedStatements: matchedStatements.length > 0 ? matchedStatements : undefined
      };
    });
    const isTruncated = parseXmlValue(xml, "IsTruncated") === "true";
    const marker = parseXmlValue(xml, "Marker");
    return { EvaluationResults: evaluationResults, IsTruncated: isTruncated, Marker: marker };
  }
}

// src/aws/ses.ts
class SESClient {
  client;
  region;
  constructor(region = "us-east-1", credentials) {
    this.region = region;
    this.client = new AWSClient(credentials);
  }
  async createEmailIdentity(params) {
    const result = await this.client.request({
      service: "email",
      region: this.region,
      method: "POST",
      path: "/v2/email/identities",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(params)
    });
    return result;
  }
  async getEmailIdentity(emailIdentity) {
    const result = await this.client.request({
      service: "email",
      region: this.region,
      method: "GET",
      path: `/v2/email/identities/${encodeURIComponent(emailIdentity)}`,
      headers: {
        "Content-Type": "application/json"
      }
    });
    return {
      IdentityType: result.IdentityType,
      IdentityName: emailIdentity,
      SendingEnabled: result.VerifiedForSendingStatus,
      VerificationStatus: result.VerificationStatus,
      DkimAttributes: result.DkimAttributes,
      MailFromAttributes: result.MailFromAttributes
    };
  }
  async putEmailIdentityMailFromAttributes(emailIdentity, params) {
    await this.client.request({
      service: "email",
      region: this.region,
      method: "PUT",
      path: `/v2/email/identities/${encodeURIComponent(emailIdentity)}/mail-from`,
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(params)
    });
  }
  async listEmailIdentities(params) {
    let path = "/v2/email/identities";
    const queryParams = [];
    if (params?.PageSize) {
      queryParams.push(`PageSize=${params.PageSize}`);
    }
    if (params?.NextToken) {
      queryParams.push(`NextToken=${encodeURIComponent(params.NextToken)}`);
    }
    if (queryParams.length > 0) {
      path += `?${queryParams.join("&")}`;
    }
    const result = await this.client.request({
      service: "email",
      region: this.region,
      method: "GET",
      path,
      headers: {
        "Content-Type": "application/json"
      }
    });
    return {
      EmailIdentities: result.EmailIdentities,
      NextToken: result.NextToken
    };
  }
  async deleteEmailIdentity(emailIdentity) {
    await this.client.request({
      service: "email",
      region: this.region,
      method: "DELETE",
      path: `/v2/email/identities/${encodeURIComponent(emailIdentity)}`,
      headers: {
        "Content-Type": "application/json"
      }
    });
  }
  async putEmailIdentityDkimAttributes(params) {
    await this.client.request({
      service: "email",
      region: this.region,
      method: "PUT",
      path: `/v2/email/identities/${encodeURIComponent(params.EmailIdentity)}/dkim`,
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify({ SigningEnabled: params.SigningEnabled })
    });
  }
  async sendEmail(params) {
    const result = await this.client.request({
      service: "email",
      region: this.region,
      method: "POST",
      path: "/v2/email/outbound-emails",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(params)
    });
    return {
      MessageId: result.MessageId
    };
  }
  async sendBulkEmail(params) {
    const result = await this.client.request({
      service: "email",
      region: this.region,
      method: "POST",
      path: "/v2/email/outbound-bulk-emails",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(params)
    });
    return {
      BulkEmailEntryResults: result.BulkEmailEntryResults
    };
  }
  async createEmailTemplate(params) {
    await this.client.request({
      service: "email",
      region: this.region,
      method: "POST",
      path: "/v2/email/templates",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(params)
    });
  }
  async getEmailTemplate(templateName) {
    const result = await this.client.request({
      service: "email",
      region: this.region,
      method: "GET",
      path: `/v2/email/templates/${encodeURIComponent(templateName)}`,
      headers: {
        "Content-Type": "application/json"
      }
    });
    return result;
  }
  async deleteEmailTemplate(templateName) {
    await this.client.request({
      service: "email",
      region: this.region,
      method: "DELETE",
      path: `/v2/email/templates/${encodeURIComponent(templateName)}`,
      headers: {
        "Content-Type": "application/json"
      }
    });
  }
  async listEmailTemplates(params) {
    let path = "/v2/email/templates";
    const queryParams = [];
    if (params?.PageSize) {
      queryParams.push(`PageSize=${params.PageSize}`);
    }
    if (params?.NextToken) {
      queryParams.push(`NextToken=${encodeURIComponent(params.NextToken)}`);
    }
    if (queryParams.length > 0) {
      path += `?${queryParams.join("&")}`;
    }
    const result = await this.client.request({
      service: "email",
      region: this.region,
      method: "GET",
      path,
      headers: {
        "Content-Type": "application/json"
      }
    });
    return result;
  }
  async getSendStatistics() {
    const result = await this.client.request({
      service: "ses",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: "Action=GetSendStatistics&Version=2010-12-01"
    });
    return {
      SendDataPoints: result.GetSendStatisticsResponse?.GetSendStatisticsResult?.SendDataPoints?.member
    };
  }
  async getSendQuota() {
    const result = await this.client.request({
      service: "ses",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: "Action=GetSendQuota&Version=2010-12-01"
    });
    const quota = result.GetSendQuotaResponse?.GetSendQuotaResult;
    return {
      Max24HourSend: quota?.Max24HourSend ? Number(quota.Max24HourSend) : undefined,
      MaxSendRate: quota?.MaxSendRate ? Number(quota.MaxSendRate) : undefined,
      SentLast24Hours: quota?.SentLast24Hours ? Number(quota.SentLast24Hours) : undefined
    };
  }
  async verifyDomain(domain) {
    const result = await this.createEmailIdentity({
      EmailIdentity: domain
    });
    return {
      dkimTokens: result.DkimAttributes?.Tokens,
      verificationStatus: result.DkimAttributes?.Status
    };
  }
  async sendSimpleEmail(params) {
    const toAddresses = Array.isArray(params.to) ? params.to : [params.to];
    const replyToAddresses = params.replyTo ? Array.isArray(params.replyTo) ? params.replyTo : [params.replyTo] : undefined;
    const body = {};
    if (params.text) {
      body.Text = { Data: params.text };
    }
    if (params.html) {
      body.Html = { Data: params.html };
    }
    return this.sendEmail({
      FromEmailAddress: params.from,
      Destination: {
        ToAddresses: toAddresses
      },
      Content: {
        Simple: {
          Subject: { Data: params.subject },
          Body: body
        }
      },
      ReplyToAddresses: replyToAddresses
    });
  }
  async sendTemplatedEmail(params) {
    const toAddresses = Array.isArray(params.to) ? params.to : [params.to];
    const replyToAddresses = params.replyTo ? Array.isArray(params.replyTo) ? params.replyTo : [params.replyTo] : undefined;
    return this.sendEmail({
      FromEmailAddress: params.from,
      Destination: {
        ToAddresses: toAddresses
      },
      Content: {
        Template: {
          TemplateName: params.templateName,
          TemplateData: JSON.stringify(params.templateData)
        }
      },
      ReplyToAddresses: replyToAddresses
    });
  }
  async getDkimRecords(domain) {
    const identity = await this.getEmailIdentity(domain);
    if (!identity.DkimAttributes?.Tokens) {
      return [];
    }
    return identity.DkimAttributes.Tokens.map((token) => ({
      name: `${token}._domainkey.${domain}`,
      type: "CNAME",
      value: `${token}.dkim.amazonses.com`
    }));
  }
  async isDomainVerified(domain) {
    try {
      const identity = await this.getEmailIdentity(domain);
      return identity.VerificationStatus === "SUCCESS" && identity.SendingEnabled === true;
    } catch {
      return false;
    }
  }
  async waitForDomainVerification(domain, maxAttempts = 60, delayMs = 30000) {
    for (let i = 0;i < maxAttempts; i++) {
      const isVerified = await this.isDomainVerified(domain);
      if (isVerified) {
        return true;
      }
      await new Promise((resolve) => setTimeout(resolve, delayMs));
    }
    return false;
  }
  buildFormBody(params) {
    const entries = Object.entries(params).filter(([, value]) => value !== undefined).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
    return entries.join("&");
  }
  async createReceiptRuleSet(ruleSetName) {
    await this.client.request({
      service: "ses",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: this.buildFormBody({
        Action: "CreateReceiptRuleSet",
        Version: "2010-12-01",
        RuleSetName: ruleSetName
      })
    });
  }
  async deleteReceiptRuleSet(ruleSetName) {
    await this.client.request({
      service: "ses",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: this.buildFormBody({
        Action: "DeleteReceiptRuleSet",
        Version: "2010-12-01",
        RuleSetName: ruleSetName
      })
    });
  }
  async setActiveReceiptRuleSet(ruleSetName) {
    await this.client.request({
      service: "ses",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: this.buildFormBody({
        Action: "SetActiveReceiptRuleSet",
        Version: "2010-12-01",
        RuleSetName: ruleSetName
      })
    });
  }
  async listReceiptRuleSets(nextToken) {
    const formParams = {
      Action: "ListReceiptRuleSets",
      Version: "2010-12-01"
    };
    if (nextToken) {
      formParams.NextToken = nextToken;
    }
    const result = await this.client.request({
      service: "ses",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: this.buildFormBody(formParams)
    });
    const ruleSetsResult = result?.ListReceiptRuleSetsResponse?.ListReceiptRuleSetsResult || result?.ListReceiptRuleSetsResult;
    const ruleSets = ruleSetsResult?.RuleSets?.member;
    return {
      RuleSets: Array.isArray(ruleSets) ? ruleSets : ruleSets ? [ruleSets] : [],
      NextToken: ruleSetsResult?.NextToken
    };
  }
  async describeReceiptRuleSet(ruleSetName) {
    const result = await this.client.request({
      service: "ses",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: this.buildFormBody({
        Action: "DescribeReceiptRuleSet",
        Version: "2010-12-01",
        RuleSetName: ruleSetName
      })
    });
    const response = result?.DescribeReceiptRuleSetResponse?.DescribeReceiptRuleSetResult || result?.DescribeReceiptRuleSetResult;
    const rules = response?.Rules?.member;
    return {
      Metadata: response?.Metadata,
      Rules: Array.isArray(rules) ? rules : rules ? [rules] : []
    };
  }
  async createReceiptRule(params) {
    const formParams = {
      Action: "CreateReceiptRule",
      Version: "2010-12-01",
      RuleSetName: params.RuleSetName,
      "Rule.Name": params.Rule.Name,
      "Rule.Enabled": params.Rule.Enabled !== false ? "true" : "false"
    };
    if (params.Rule.TlsPolicy) {
      formParams["Rule.TlsPolicy"] = params.Rule.TlsPolicy;
    }
    if (params.Rule.ScanEnabled !== undefined) {
      formParams["Rule.ScanEnabled"] = params.Rule.ScanEnabled ? "true" : "false";
    }
    if (params.After) {
      formParams.After = params.After;
    }
    if (params.Rule.Recipients) {
      params.Rule.Recipients.forEach((recipient, index) => {
        formParams[`Rule.Recipients.member.${index + 1}`] = recipient;
      });
    }
    params.Rule.Actions.forEach((action, index) => {
      const actionNum = index + 1;
      if (action.S3Action) {
        formParams[`Rule.Actions.member.${actionNum}.S3Action.BucketName`] = action.S3Action.BucketName;
        if (action.S3Action.ObjectKeyPrefix) {
          formParams[`Rule.Actions.member.${actionNum}.S3Action.ObjectKeyPrefix`] = action.S3Action.ObjectKeyPrefix;
        }
        if (action.S3Action.KmsKeyArn) {
          formParams[`Rule.Actions.member.${actionNum}.S3Action.KmsKeyArn`] = action.S3Action.KmsKeyArn;
        }
      }
      if (action.LambdaAction) {
        formParams[`Rule.Actions.member.${actionNum}.LambdaAction.FunctionArn`] = action.LambdaAction.FunctionArn;
        formParams[`Rule.Actions.member.${actionNum}.LambdaAction.InvocationType`] = action.LambdaAction.InvocationType || "Event";
      }
      if (action.SNSAction) {
        formParams[`Rule.Actions.member.${actionNum}.SNSAction.TopicArn`] = action.SNSAction.TopicArn;
        if (action.SNSAction.Encoding) {
          formParams[`Rule.Actions.member.${actionNum}.SNSAction.Encoding`] = action.SNSAction.Encoding;
        }
      }
      if (action.StopAction) {
        formParams[`Rule.Actions.member.${actionNum}.StopAction.Scope`] = action.StopAction.Scope;
        if (action.StopAction.TopicArn) {
          formParams[`Rule.Actions.member.${actionNum}.StopAction.TopicArn`] = action.StopAction.TopicArn;
        }
      }
    });
    await this.client.request({
      service: "ses",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: this.buildFormBody(formParams)
    });
  }
  async deleteReceiptRule(ruleSetName, ruleName) {
    await this.client.request({
      service: "ses",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: this.buildFormBody({
        Action: "DeleteReceiptRule",
        Version: "2010-12-01",
        RuleSetName: ruleSetName,
        RuleName: ruleName
      })
    });
  }
  async receiptRuleSetExists(ruleSetName) {
    try {
      await this.describeReceiptRuleSet(ruleSetName);
      return true;
    } catch (error) {
      if (error.code === "RuleSetDoesNotExist" || error.statusCode === 400) {
        return false;
      }
      throw error;
    }
  }
  async getActiveReceiptRuleSet() {
    const result = await this.client.request({
      service: "ses",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: this.buildFormBody({
        Action: "DescribeActiveReceiptRuleSet",
        Version: "2010-12-01"
      })
    });
    const response = result?.DescribeActiveReceiptRuleSetResponse?.DescribeActiveReceiptRuleSetResult || result?.DescribeActiveReceiptRuleSetResult;
    if (!response?.Metadata) {
      return null;
    }
    const rules = response?.Rules?.member;
    return {
      Metadata: response?.Metadata,
      Rules: Array.isArray(rules) ? rules : rules ? [rules] : []
    };
  }
  async updateReceiptRule(params) {
    const formParams = {
      Action: "UpdateReceiptRule",
      Version: "2010-12-01",
      RuleSetName: params.RuleSetName,
      "Rule.Name": params.Rule.Name
    };
    if (params.Rule.Enabled !== undefined) {
      formParams["Rule.Enabled"] = params.Rule.Enabled ? "true" : "false";
    }
    if (params.Rule.TlsPolicy) {
      formParams["Rule.TlsPolicy"] = params.Rule.TlsPolicy;
    }
    if (params.Rule.ScanEnabled !== undefined) {
      formParams["Rule.ScanEnabled"] = params.Rule.ScanEnabled ? "true" : "false";
    }
    if (params.Rule.Recipients) {
      params.Rule.Recipients.forEach((recipient, index) => {
        formParams[`Rule.Recipients.member.${index + 1}`] = recipient;
      });
    }
    params.Rule.Actions.forEach((action, index) => {
      const actionNum = index + 1;
      if (action.S3Action) {
        formParams[`Rule.Actions.member.${actionNum}.S3Action.BucketName`] = action.S3Action.BucketName;
        if (action.S3Action.ObjectKeyPrefix) {
          formParams[`Rule.Actions.member.${actionNum}.S3Action.ObjectKeyPrefix`] = action.S3Action.ObjectKeyPrefix;
        }
        if (action.S3Action.KmsKeyArn) {
          formParams[`Rule.Actions.member.${actionNum}.S3Action.KmsKeyArn`] = action.S3Action.KmsKeyArn;
        }
      }
      if (action.LambdaAction) {
        formParams[`Rule.Actions.member.${actionNum}.LambdaAction.FunctionArn`] = action.LambdaAction.FunctionArn;
        formParams[`Rule.Actions.member.${actionNum}.LambdaAction.InvocationType`] = action.LambdaAction.InvocationType || "Event";
      }
      if (action.SNSAction) {
        formParams[`Rule.Actions.member.${actionNum}.SNSAction.TopicArn`] = action.SNSAction.TopicArn;
        if (action.SNSAction.Encoding) {
          formParams[`Rule.Actions.member.${actionNum}.SNSAction.Encoding`] = action.SNSAction.Encoding;
        }
      }
      if (action.StopAction) {
        formParams[`Rule.Actions.member.${actionNum}.StopAction.Scope`] = action.StopAction.Scope;
        if (action.StopAction.TopicArn) {
          formParams[`Rule.Actions.member.${actionNum}.StopAction.TopicArn`] = action.StopAction.TopicArn;
        }
      }
    });
    await this.client.request({
      service: "ses",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: this.buildFormBody(formParams)
    });
  }
  async sendRawEmail(params) {
    const rawMessageBase64 = Buffer.from(params.rawMessage).toString("base64");
    const formParams = {
      Action: "SendRawEmail",
      Version: "2010-12-01",
      Source: params.source,
      "RawMessage.Data": rawMessageBase64
    };
    params.destinations.forEach((dest, index) => {
      formParams[`Destinations.member.${index + 1}`] = dest;
    });
    const result = await this.client.request({
      service: "ses",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: this.buildFormBody(formParams)
    });
    const response = result?.SendRawEmailResponse?.SendRawEmailResult || result?.SendRawEmailResult;
    return {
      MessageId: response?.MessageId
    };
  }
  async getSuppressedDestination(emailAddress) {
    try {
      const result = await this.client.request({
        service: "ses",
        region: this.region,
        method: "GET",
        path: `/v2/email/suppression/addresses/${encodeURIComponent(emailAddress)}`
      });
      return result?.SuppressedDestination || null;
    } catch (error) {
      if (error.message?.includes("404") || error.message?.includes("NotFoundException")) {
        return null;
      }
      throw error;
    }
  }
  async deleteSuppressedDestination(emailAddress) {
    await this.client.request({
      service: "ses",
      region: this.region,
      method: "DELETE",
      path: `/v2/email/suppression/addresses/${encodeURIComponent(emailAddress)}`
    });
  }
}

// src/aws/email.ts
class EmailClient {
  ses;
  s3;
  iam;
  route53;
  region;
  domain;
  defaultFrom;
  constructor(options = {}) {
    this.region = options.region || "us-east-1";
    this.domain = options.domain;
    this.defaultFrom = options.defaultFrom;
    this.ses = new SESClient(this.region);
    this.s3 = new S3Client(this.region);
    this.iam = new IAMClient(this.region);
    this.route53 = new Route53Client(this.region);
  }
  async send(options) {
    const from = options.from || this.defaultFrom;
    if (!from) {
      throw new Error("From address is required. Set defaultFrom in constructor or provide from in options.");
    }
    const fromAddress = options.fromName ? `${options.fromName} <${from}>` : from;
    const toAddresses = Array.isArray(options.to) ? options.to : [options.to];
    if (!options.attachments || options.attachments.length === 0) {
      const result2 = await this.ses.sendSimpleEmail({
        from: fromAddress,
        to: toAddresses,
        subject: options.subject,
        text: options.text,
        html: options.html,
        replyTo: options.replyTo
      });
      return { messageId: result2.MessageId || "" };
    }
    const rawEmail = this.buildRawEmail(options, fromAddress, toAddresses);
    const result = await this.ses.sendEmail({
      FromEmailAddress: fromAddress,
      Destination: {
        ToAddresses: toAddresses,
        CcAddresses: options.cc ? Array.isArray(options.cc) ? options.cc : [options.cc] : undefined,
        BccAddresses: options.bcc ? Array.isArray(options.bcc) ? options.bcc : [options.bcc] : undefined
      },
      Content: {
        Raw: {
          Data: Buffer.from(rawEmail).toString("base64")
        }
      }
    });
    return { messageId: result.MessageId || "" };
  }
  async sendTemplate(options) {
    const from = options.from || this.defaultFrom;
    if (!from) {
      throw new Error("From address is required");
    }
    const fromAddress = options.fromName ? `${options.fromName} <${from}>` : from;
    const result = await this.ses.sendTemplatedEmail({
      from: fromAddress,
      to: options.to,
      templateName: options.templateName,
      templateData: options.templateData,
      replyTo: options.replyTo
    });
    return { messageId: result.MessageId || "" };
  }
  async sendBulk(options) {
    const from = options.from || this.defaultFrom;
    if (!from) {
      throw new Error("From address is required");
    }
    const entries = options.recipients.map((r) => ({
      Destination: {
        ToAddresses: Array.isArray(r.to) ? r.to : [r.to]
      },
      ReplacementEmailContent: r.templateData ? {
        ReplacementTemplate: {
          ReplacementTemplateData: JSON.stringify(r.templateData)
        }
      } : undefined
    }));
    const result = await this.ses.sendBulkEmail({
      FromEmailAddress: from,
      BulkEmailEntries: entries,
      DefaultContent: {
        Template: {
          TemplateName: options.templateName,
          TemplateData: JSON.stringify(options.defaultTemplateData)
        }
      }
    });
    return {
      results: result.BulkEmailEntryResults?.map((r) => ({
        status: r.Status || "UNKNOWN",
        messageId: r.MessageId,
        error: r.Error
      })) || []
    };
  }
  async setupDomain(domain) {
    let identity;
    try {
      identity = await this.ses.getEmailIdentity(domain);
    } catch {
      const createResult = await this.ses.createEmailIdentity({ EmailIdentity: domain });
      identity = {
        VerificationStatus: createResult.DkimAttributes?.Status,
        DkimAttributes: createResult.DkimAttributes,
        SendingEnabled: createResult.VerifiedForSendingStatus
      };
    }
    try {
      await this.ses.putEmailIdentityDkimAttributes({
        EmailIdentity: domain,
        SigningEnabled: true
      });
    } catch {}
    try {
      await this.ses.putEmailIdentityMailFromAttributes(domain, {
        MailFromDomain: `mail.${domain}`,
        BehaviorOnMxFailure: "USE_DEFAULT_VALUE"
      });
    } catch {}
    const dkimRecords = await this.ses.getDkimRecords(domain);
    return {
      domainVerified: identity.SendingEnabled === true,
      dkimStatus: identity.DkimAttributes?.Status || "UNKNOWN",
      dkimTokens: identity.DkimAttributes?.Tokens,
      mailFromStatus: identity.MailFromAttributes?.MailFromDomainStatus
    };
  }
  async getDnsRecords(domain) {
    const records = [];
    const dkimRecords = await this.ses.getDkimRecords(domain);
    for (const record of dkimRecords) {
      records.push({
        type: record.type,
        name: record.name,
        value: record.value,
        ttl: 1800
      });
    }
    records.push({
      type: "MX",
      name: domain,
      value: `inbound-smtp.${this.region}.amazonaws.com`,
      priority: 10,
      ttl: 3600
    });
    records.push({
      type: "MX",
      name: `mail.${domain}`,
      value: `feedback-smtp.${this.region}.amazonses.com`,
      priority: 10,
      ttl: 3600
    });
    records.push({
      type: "TXT",
      name: `mail.${domain}`,
      value: "v=spf1 include:amazonses.com ~all",
      ttl: 3600
    });
    records.push({
      type: "TXT",
      name: `_dmarc.${domain}`,
      value: `v=DMARC1;p=quarantine;pct=25;rua=mailto:dmarcreports@${domain}`,
      ttl: 3600
    });
    return records;
  }
  async isDomainReady(domain) {
    try {
      const identity = await this.ses.getEmailIdentity(domain);
      return identity.SendingEnabled === true && identity.DkimAttributes?.Status === "SUCCESS";
    } catch {
      return false;
    }
  }
  async setupReceiving(config) {
    const policy = {
      Version: "2012-10-17",
      Statement: [
        {
          Sid: "AllowSESPuts",
          Effect: "Allow",
          Principal: { Service: "ses.amazonaws.com" },
          Action: "s3:PutObject",
          Resource: `arn:aws:s3:::${config.bucketName}/*`,
          Condition: {
            StringEquals: { "AWS:SourceAccount": config.accountId }
          }
        }
      ]
    };
    await this.s3.putBucketPolicy(config.bucketName, policy);
    try {
      await this.ses.createReceiptRuleSet(config.ruleSetName);
    } catch (e) {
      if (!e.message?.includes("already exists") && e.code !== "AlreadyExists") {
        throw e;
      }
    }
    const actions = [
      {
        S3Action: {
          BucketName: config.bucketName,
          ObjectKeyPrefix: config.prefix || "inbox/"
        }
      }
    ];
    if (config.lambdaArn) {
      actions.push({
        LambdaAction: {
          FunctionArn: config.lambdaArn,
          InvocationType: "Event"
        }
      });
    }
    try {
      await this.ses.createReceiptRule({
        RuleSetName: config.ruleSetName,
        Rule: {
          Name: config.ruleName,
          Enabled: true,
          TlsPolicy: "Optional",
          Recipients: config.recipients || [config.domain],
          ScanEnabled: config.scanEnabled !== false,
          Actions: actions
        }
      });
    } catch (e) {
      if (e.message?.includes("already exists")) {
        await this.ses.deleteReceiptRule(config.ruleSetName, config.ruleName);
        await this.ses.createReceiptRule({
          RuleSetName: config.ruleSetName,
          Rule: {
            Name: config.ruleName,
            Enabled: true,
            TlsPolicy: "Optional",
            Recipients: config.recipients || [config.domain],
            ScanEnabled: config.scanEnabled !== false,
            Actions: actions
          }
        });
      } else {
        throw e;
      }
    }
    await this.ses.setActiveReceiptRuleSet(config.ruleSetName);
  }
  async getIncomingEmails(options) {
    const objects = await this.s3.list({
      bucket: options.bucket,
      prefix: options.prefix || "incoming/",
      maxKeys: options.maxResults || 100
    });
    return objects.map((obj) => ({
      key: obj.Key || "",
      lastModified: obj.LastModified || "",
      size: obj.Size || 0
    }));
  }
  async readEmail(options) {
    return await this.s3.getObject(options.bucket, options.key);
  }
  async createSmtpCredentials(options) {
    const iamUsername = `ses-smtp-${options.username.replace(/[^a-zA-Z0-9]/g, "-")}`;
    const { AWSClient: AWSClient2 } = await import("./chunk-x9s0cqfx.js");
    const client = new AWSClient2;
    const buildBody = (action, params) => {
      const allParams = { Action: action, Version: "2010-05-08", ...params };
      return Object.entries(allParams).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&");
    };
    try {
      await client.request({
        service: "iam",
        region: "us-east-1",
        method: "POST",
        path: "/",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: buildBody("CreateUser", { UserName: iamUsername })
      });
    } catch (e) {
      if (!e.message?.includes("EntityAlreadyExists")) {
        throw e;
      }
    }
    const policy = {
      Version: "2012-10-17",
      Statement: [
        {
          Effect: "Allow",
          Action: "ses:SendRawEmail",
          Resource: "*",
          Condition: {
            StringLike: {
              "ses:FromAddress": `*@${options.domain}`
            }
          }
        }
      ]
    };
    const policyName = `ses-smtp-policy-${options.domain.replace(/\./g, "-")}`;
    try {
      await client.request({
        service: "iam",
        region: "us-east-1",
        method: "POST",
        path: "/",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: buildBody("PutUserPolicy", {
          UserName: iamUsername,
          PolicyName: policyName,
          PolicyDocument: JSON.stringify(policy)
        })
      });
    } catch {}
    const keyResponse = await client.request({
      service: "iam",
      region: "us-east-1",
      method: "POST",
      path: "/",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: buildBody("CreateAccessKey", { UserName: iamUsername })
    });
    const accessKey = keyResponse?.CreateAccessKeyResult?.AccessKey;
    if (!accessKey?.AccessKeyId || !accessKey?.SecretAccessKey) {
      throw new Error("Failed to create access key");
    }
    const smtpPassword = this.deriveSmtpPassword(accessKey.SecretAccessKey);
    return {
      username: accessKey.AccessKeyId,
      password: smtpPassword,
      server: `email-smtp.${this.region}.amazonaws.com`,
      port: 587
    };
  }
  deriveSmtpPassword(secretAccessKey) {
    const crypto = __require("node:crypto");
    const message = "SendRawEmail";
    const versionInBytes = Buffer.from([4]);
    let signature = crypto.createHmac("sha256", `AWS4${secretAccessKey}`).update("11111111").digest();
    signature = crypto.createHmac("sha256", signature).update(this.region).digest();
    signature = crypto.createHmac("sha256", signature).update("ses").digest();
    signature = crypto.createHmac("sha256", signature).update("aws4_request").digest();
    signature = crypto.createHmac("sha256", signature).update(message).digest();
    const signatureWithVersion = Buffer.concat([versionInBytes, signature]);
    return signatureWithVersion.toString("base64");
  }
  async createTemplate(options) {
    await this.ses.createEmailTemplate({
      TemplateName: options.name,
      TemplateContent: {
        Subject: options.subject,
        Text: options.text,
        Html: options.html
      }
    });
  }
  async getTemplate(name) {
    try {
      const result = await this.ses.getEmailTemplate(name);
      return {
        name: result.TemplateName || name,
        subject: result.TemplateContent?.Subject,
        text: result.TemplateContent?.Text,
        html: result.TemplateContent?.Html
      };
    } catch {
      return null;
    }
  }
  async deleteTemplate(name) {
    await this.ses.deleteEmailTemplate(name);
  }
  async listTemplates() {
    const result = await this.ses.listEmailTemplates();
    return result.TemplatesMetadata?.map((t) => ({
      name: t.TemplateName || "",
      createdAt: t.CreatedTimestamp
    })) || [];
  }
  async deploy(config) {
    const ruleSetName = `${config.appName}-${config.environment}-email-rules`;
    const ruleName = `${config.appName}-inbound-email`;
    const bucketName = config.storage?.bucketName || `${config.appName}-${config.environment}-email`;
    const domainSetup = await this.setupDomain(config.domain);
    const buckets = await this.s3.listBuckets();
    const bucketExists = buckets.Buckets?.some((b) => b.Name === bucketName);
    if (!bucketExists) {
      await this.s3.createBucket(bucketName);
    }
    await this.setupReceiving({
      domain: config.domain,
      ruleSetName,
      ruleName,
      bucketName,
      prefix: config.storage?.prefix || "inbox/",
      accountId: config.accountId,
      recipients: config.catchAll ? [config.domain] : config.mailboxes,
      scanEnabled: true
    });
    const dnsRecords = await this.getDnsRecords(config.domain);
    return {
      success: true,
      domainVerified: domainSetup.domainVerified,
      dkimStatus: domainSetup.dkimStatus,
      receiptRuleSet: ruleSetName,
      storageBucket: bucketName,
      dnsRecords
    };
  }
  async undeploy(config) {
    const ruleSetName = `${config.appName}-${config.environment}-email-rules`;
    const ruleName = `${config.appName}-inbound-email`;
    const bucketName = `${config.appName}-${config.environment}-email`;
    try {
      await this.ses.deleteReceiptRule(ruleSetName, ruleName);
    } catch {}
    try {
      await this.ses.deleteReceiptRuleSet(ruleSetName);
    } catch {}
    if (config.deleteBucket) {
      try {
        await this.s3.emptyAndDeleteBucket(bucketName);
      } catch {}
    }
  }
  async getSendingStats() {
    const quota = await this.ses.getSendQuota();
    return {
      sentLast24Hours: quota.SentLast24Hours || 0,
      maxSendRate: quota.MaxSendRate || 0,
      max24HourSend: quota.Max24HourSend || 0
    };
  }
  buildRawEmail(options, from, to) {
    const boundary = `----=_Part_${Date.now()}_${Math.random().toString(36).substring(2)}`;
    let email = "";
    email += `From: ${from}\r
`;
    email += `To: ${to.join(", ")}\r
`;
    if (options.cc) {
      const ccList = Array.isArray(options.cc) ? options.cc : [options.cc];
      email += `Cc: ${ccList.join(", ")}\r
`;
    }
    email += `Subject: ${options.subject}\r
`;
    email += `MIME-Version: 1.0\r
`;
    email += `Content-Type: multipart/mixed; boundary="${boundary}"\r
`;
    email += `\r
`;
    if (options.text || options.html) {
      email += `--${boundary}\r
`;
      if (options.html && options.text) {
        const altBoundary = `----=_Alt_${Date.now()}`;
        email += `Content-Type: multipart/alternative; boundary="${altBoundary}"\r
`;
        email += `\r
`;
        email += `--${altBoundary}\r
`;
        email += `Content-Type: text/plain; charset="UTF-8"\r
`;
        email += `\r
`;
        email += `${options.text}\r
`;
        email += `--${altBoundary}\r
`;
        email += `Content-Type: text/html; charset="UTF-8"\r
`;
        email += `\r
`;
        email += `${options.html}\r
`;
        email += `--${altBoundary}--\r
`;
      } else if (options.html) {
        email += `Content-Type: text/html; charset="UTF-8"\r
`;
        email += `\r
`;
        email += `${options.html}\r
`;
      } else {
        email += `Content-Type: text/plain; charset="UTF-8"\r
`;
        email += `\r
`;
        email += `${options.text}\r
`;
      }
    }
    if (options.attachments) {
      for (const attachment of options.attachments) {
        email += `--${boundary}\r
`;
        email += `Content-Type: ${attachment.contentType || "application/octet-stream"}; name="${attachment.filename}"\r
`;
        email += `Content-Transfer-Encoding: base64\r
`;
        email += `Content-Disposition: attachment; filename="${attachment.filename}"\r
`;
        email += `\r
`;
        email += `${attachment.content}\r
`;
      }
    }
    email += `--${boundary}--\r
`;
    return email;
  }
}
var email = new EmailClient;

export { IAMClient, SESClient, EmailClient, email };
