{"version":3,"sources":["../src/errors.ts","../src/utils/html-to-text.ts","../src/utils/headers.ts","../src/utils/validation.ts","../src/workers-client.ts"],"names":["email","zEmail"],"mappings":"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","file":"workers.mjs","sourcesContent":["export class WrapsEmailError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = 'WrapsEmailError';\n  }\n}\n\nexport class ValidationError extends WrapsEmailError {\n  public readonly field?: string;\n\n  constructor(message: string, field?: string) {\n    super(message);\n    this.name = 'ValidationError';\n    this.field = field;\n  }\n}\n\nexport class SESError extends WrapsEmailError {\n  public readonly code: string;\n  public readonly requestId: string;\n  public readonly retryable: boolean;\n\n  constructor(message: string, code: string, requestId: string, retryable: boolean) {\n    super(message);\n    this.name = 'SESError';\n    this.code = code;\n    this.requestId = requestId;\n    this.retryable = retryable;\n  }\n}\n\nexport class DynamoDBError extends WrapsEmailError {\n  public readonly code: string;\n  public readonly requestId: string;\n  public readonly retryable: boolean;\n\n  constructor(message: string, code: string, requestId: string, retryable: boolean) {\n    super(message);\n    this.name = 'DynamoDBError';\n    this.code = code;\n    this.requestId = requestId;\n    this.retryable = retryable;\n  }\n}\n\n/**\n * SES refused the send because an identity involved isn't verified in the\n * region the request went to. Extends {@link SESError} so existing\n * `instanceof SESError` handling keeps working.\n *\n * Two unrelated causes produce this one AWS error — a region mismatch and the\n * SES sandbox — so {@link SandboxError.region} records which region the request\n * actually used, and the message walks through both.\n */\nexport class SandboxError extends SESError {\n  /** The region this client sent to, when it could be resolved. */\n  public readonly region?: string;\n\n  constructor(\n    message: string,\n    code: string,\n    requestId: string,\n    retryable: boolean,\n    region?: string\n  ) {\n    super(message, code, requestId, retryable);\n    this.name = 'SandboxError';\n    this.region = region;\n  }\n}\n\n/**\n * The AWS credential chain produced nothing usable, so no request was ever\n * signed. Extends {@link WrapsEmailError} so a single `instanceof` check\n * really does cover every error this SDK throws.\n */\nexport class CredentialsError extends WrapsEmailError {\n  /** The underlying AWS SDK error, kept for debugging. */\n  public readonly cause?: unknown;\n\n  constructor(message: string, cause?: unknown) {\n    super(message);\n    this.name = 'CredentialsError';\n    this.cause = cause;\n  }\n}\n\n/**\n * AWS pre-verifies this address, so a sandboxed account can send to it with no\n * recipient verification and get a real Delivery event back. Mirrors\n * `SES_SIMULATOR_ADDRESSES.SUCCESS` in the wraps CLI\n * (`packages/cli/src/utils/email/ses-simulator.ts`) and `SES_SIMULATOR_SUCCESS`\n * in `@wraps.dev/mcp`.\n */\nexport const SES_SIMULATOR_SUCCESS = 'success@simulator.amazonses.com';\n\n// Deliberately neutral: every way credentials can be supplied, listed without\n// ranking one over another. Wording tracks CREDENTIAL_OPTIONS in the wraps CLI\n// at packages/cli/src/utils/shared/errors.ts.\nconst CREDENTIAL_OPTIONS = `Wraps couldn't find working AWS credentials. Any of these work:\n\nAWS SSO:\n  aws configure sso\n  aws sso login\n\nIAM access keys:\n  aws configure\n\nEnvironment variables:\n  export AWS_ACCESS_KEY_ID=<your-key>\n  export AWS_SECRET_ACCESS_KEY=<your-secret>\n\nExisting profile:\n  export AWS_PROFILE=<profile-name>\n\nPassed to the client:\n  new WrapsEmail({ credentials: { accessKeyId, secretAccessKey } })`;\n\n/**\n * True when the AWS credential chain itself failed, meaning nothing was ever\n * sent. AWS SDK v3 error names are unreliable, so check name AND message.\n * An error carrying `$metadata` reached AWS and is therefore never this.\n */\nexport function isCredentialsChainError(error: unknown): boolean {\n  const err = error as { name?: string; message?: string; $metadata?: unknown };\n  if (err?.$metadata) {\n    return false;\n  }\n  const name = typeof err?.name === 'string' ? err.name : '';\n  const message = typeof err?.message === 'string' ? err.message : '';\n  return (\n    name === 'CredentialsProviderError' ||\n    name === 'TokenProviderError' ||\n    message.includes('Could not load credentials from any providers') ||\n    message.includes('Credential is missing') ||\n    (message.includes('Profile') && message.includes('could not be found')) ||\n    message.includes('SSO session associated with this profile has expired')\n  );\n}\n\n/**\n * True when SES rejected the send because an identity is not verified in the\n * region the request went to.\n *\n * Narrower on purpose than `isUnverifiedRecipientError()` in `@wraps.dev/mcp`,\n * which treats every `MessageRejected` as a sandbox rejection — SES also uses\n * that code for suspended and paused accounts, where sandbox guidance is wrong.\n */\nexport function isUnverifiedIdentityError(error: unknown): boolean {\n  const err = error as { name?: string; message?: string };\n  const message = typeof err?.message === 'string' ? err.message : '';\n  return /not verified/i.test(message);\n}\n\n/**\n * Guidance for an unverified-identity rejection.\n *\n * A region mismatch and a sandbox block produce the *same* AWS text, so the\n * message names the region actually used and separates the two causes rather\n * than sending the developer off to re-verify an identity that is already\n * verified somewhere else.\n */\nexport function buildUnverifiedIdentityGuidance(\n  originalMessage: string,\n  region: string | undefined\n): string {\n  const where = region ? `region ${region}` : 'the region this client resolved';\n  const regionFlag = region ? ` --region ${region}` : '';\n\n  return [\n    `SES rejected this send: ${originalMessage}`,\n    '',\n    `The identity check ran in ${where}. Two unrelated things produce this error — rule them out in this order:`,\n    '',\n    `1. Region mismatch. SES identities are per-region, and this client used ${where}. If you verified the domain or address in a different region, ${where} has never heard of it and re-verifying will not help. Set AWS_REGION, or pass \\`region\\` to the WrapsEmail constructor, to send where the identity lives.`,\n    '',\n    '2. SES sandbox. A sandboxed AWS account can only send TO verified recipients. Options, cheapest first:',\n    `   a. Send to the AWS mailbox simulator instead: to: \"${SES_SIMULATOR_SUCCESS}\". AWS pre-verifies it, so it proves your sender and pipeline work with no production access, and produces a real Delivery event.`,\n    '   b. Verify the intended recipient as an SES identity in this account, then retry. Verified identities can both send and receive while in the sandbox.',\n    '   c. Request SES production access to send to anyone. That is an AWS support review, and this SDK cannot do it for you.',\n    '',\n    'To tell which one you are hitting:',\n    `  aws sesv2 get-account${regionFlag}            # productionAccessEnabled: false means sandbox`,\n    `  aws sesv2 list-email-identities${regionFlag}  # what is verified in this region`,\n    `  npx wraps email status${regionFlag}`,\n  ].join('\\n');\n}\n\n/**\n * Map an AWS SDK v3 client error into this SDK's error hierarchy. AWS SDK\n * errors carry `$metadata` (with `requestId`) and an optional\n * `$retryable.throttling` flag. Credential-chain failures never reach AWS and\n * so carry neither — they become a {@link CredentialsError}. Non-AWS errors\n * are returned unchanged.\n *\n * @param error - The caught error from an AWS SDK `.send()` call.\n * @param fallbackMessage - Message used when the error has no `.message`.\n * @param options.region - Region the failing request used, named in\n *   unverified-identity guidance so a region mismatch is distinguishable from\n *   a sandbox block.\n * @returns A `CredentialsError`, `SandboxError`, or `SESError` when the error\n *   is recognized, else the original error.\n */\nexport function mapAwsSdkError(\n  error: unknown,\n  fallbackMessage = 'SES request failed',\n  options: { region?: string } = {}\n): Error {\n  const err = error as {\n    $metadata?: { requestId?: string };\n    $retryable?: { throttling?: boolean };\n    message?: string;\n    name?: string;\n  };\n\n  if (isCredentialsChainError(error)) {\n    const detail = err.message || fallbackMessage;\n    return new CredentialsError(`${CREDENTIAL_OPTIONS}\\n\\nOriginal AWS error: ${detail}`, error);\n  }\n\n  if (err.$metadata) {\n    const message = err.message || fallbackMessage;\n    const code = err.name || 'Unknown';\n    const requestId = err.$metadata.requestId || 'unknown';\n    const retryable = err.$retryable?.throttling || false;\n\n    if (isUnverifiedIdentityError(error)) {\n      return new SandboxError(\n        buildUnverifiedIdentityGuidance(message, options.region),\n        code,\n        requestId,\n        retryable,\n        options.region\n      );\n    }\n\n    return new SESError(message, code, requestId, retryable);\n  }\n\n  return error as Error;\n}\n","/**\n * Convert HTML to plain text for email fallback.\n *\n * Handles common email HTML patterns: block elements, line breaks,\n * lists, links, and HTML entities. No external dependencies.\n */\nexport function htmlToPlainText(html: string): string {\n  let text = html;\n\n  // Replace <br> variants with newlines\n  text = text.replace(/<br\\s*\\/?>/gi, '\\n');\n\n  // Replace <hr> with a separator\n  text = text.replace(/<hr\\s*\\/?>/gi, '\\n---\\n');\n\n  // Extract href from links: <a href=\"url\">text</a> → text (url)\n  text = text.replace(/<a[^>]+href=\"([^\"]*)\"[^>]*>([\\s\\S]*?)<\\/a>/gi, (_, href, linkText) => {\n    const cleaned = linkText.replace(/<[^>]+>/g, '').trim();\n    if (!cleaned || cleaned === href) return href;\n    return `${cleaned} (${href})`;\n  });\n\n  // Add newlines before block-level elements\n  text = text.replace(\n    /<\\/(p|div|h[1-6]|tr|blockquote|section|article|header|footer|main|aside|nav)>/gi,\n    '\\n\\n'\n  );\n  text = text.replace(\n    /<(p|div|h[1-6]|tr|blockquote|section|article|header|footer|main|aside|nav)[\\s>]/gi,\n    '\\n'\n  );\n\n  // Handle list items\n  text = text.replace(/<li(?:\\s[^>]*)?>/gi, '\\n- ');\n  text = text.replace(/<\\/li>/gi, '');\n\n  // Handle table cells with spacing\n  text = text.replace(/<\\/td>/gi, '\\t');\n  text = text.replace(/<\\/th>/gi, '\\t');\n\n  // Strip remaining HTML tags\n  text = text.replace(/<[^>]+>/g, '');\n\n  // Decode HTML entities\n  text = text\n    .replace(/&nbsp;/gi, ' ')\n    .replace(/&amp;/gi, '&')\n    .replace(/&lt;/gi, '<')\n    .replace(/&gt;/gi, '>')\n    .replace(/&quot;/gi, '\"')\n    .replace(/&#39;/gi, \"'\")\n    .replace(/&apos;/gi, \"'\")\n    .replace(/&#(\\d+);/g, (match, code) => {\n      const cp = Number.parseInt(code, 10);\n      return cp <= 0x10ffff ? String.fromCodePoint(cp) : match;\n    })\n    .replace(/&#x([0-9a-f]+);/gi, (match, hex) => {\n      const cp = Number.parseInt(hex, 16);\n      return cp <= 0x10ffff ? String.fromCodePoint(cp) : match;\n    });\n\n  // Collapse runs of whitespace (but preserve newlines)\n  text = text.replace(/[^\\S\\n]+/g, ' ');\n\n  // Collapse 3+ consecutive newlines into 2\n  text = text.replace(/\\n{3,}/g, '\\n\\n');\n\n  // Trim each line\n  text = text\n    .split('\\n')\n    .map((line) => line.trim())\n    .join('\\n');\n\n  return text.trim();\n}\n","import { ValidationError } from '../errors';\n\n/**\n * Reject a value destined for a MIME header line if it contains CR or LF.\n * Embedded newlines are the email-header-injection vector.\n */\nexport function assertNoHeaderInjection(value: string, field: string): void {\n  if (/[\\r\\n]/.test(value)) {\n    throw new ValidationError(`Illegal newline in header field: ${field}`, field);\n  }\n}\n\n/** Same check, returns the value for inline use. */\nexport function sanitizeHeaderValue(value: string, field: string): string {\n  assertNoHeaderInjection(value, field);\n  return value;\n}\n","import { safeParse, email as zEmail } from 'zod/mini';\nimport { ValidationError } from '../errors';\nimport type { EmailAddress, SendEmailParams } from '../types';\nimport { assertNoHeaderInjection } from './headers';\n\n/**\n * Normalize email address to string format\n */\nexport function normalizeEmailAddress(address: string | EmailAddress): string {\n  if (typeof address === 'string') {\n    return address;\n  }\n\n  if (address.name) {\n    return `\"${address.name}\" <${address.email}>`;\n  }\n\n  return address.email;\n}\n\n/**\n * Normalize array of email addresses to string array\n */\nexport function normalizeEmailAddresses(\n  addresses: string | string[] | EmailAddress | EmailAddress[] | (string | EmailAddress)[]\n): string[] {\n  const addressArray = Array.isArray(addresses) ? addresses : [addresses];\n  return addressArray.map(normalizeEmailAddress);\n}\n\n/**\n * Validate email parameters\n */\nexport function validateEmailParams(params: SendEmailParams): void {\n  // Validate required fields\n  if (!params.from) {\n    throw new ValidationError('Missing required field: from', 'from');\n  }\n\n  if (!params.to) {\n    throw new ValidationError('Missing required field: to', 'to');\n  }\n\n  if (!params.subject) {\n    throw new ValidationError('Missing required field: subject', 'subject');\n  }\n\n  // Validate that either html or react is provided (but not both)\n  if (!params.html && !params.react && !params.text) {\n    throw new ValidationError('Must provide at least one of: html, text, or react', 'html');\n  }\n\n  if (params.html && params.react) {\n    throw new ValidationError('Cannot provide both \"html\" and \"react\" parameters', 'html');\n  }\n\n  // Validate email addresses (basic validation)\n  validateEmailAddress(params.from, 'from');\n\n  const toAddresses = Array.isArray(params.to) ? params.to : [params.to];\n  for (const [idx, addr] of toAddresses.entries()) {\n    validateEmailAddress(addr, `to[${idx}]`);\n  }\n\n  if (params.cc) {\n    const ccAddresses = Array.isArray(params.cc) ? params.cc : [params.cc];\n    for (const [idx, addr] of ccAddresses.entries()) {\n      validateEmailAddress(addr, `cc[${idx}]`);\n    }\n  }\n\n  if (params.bcc) {\n    const bccAddresses = Array.isArray(params.bcc) ? params.bcc : [params.bcc];\n    for (const [idx, addr] of bccAddresses.entries()) {\n      validateEmailAddress(addr, `bcc[${idx}]`);\n    }\n  }\n\n  if (params.replyTo) {\n    const replyToAddresses = Array.isArray(params.replyTo) ? params.replyTo : [params.replyTo];\n    for (const [idx, addr] of replyToAddresses.entries()) {\n      validateEmailAddress(addr, `replyTo[${idx}]`);\n    }\n  }\n}\n\n// Every address error states the expected format, gives a copyable example, and\n// echoes what was actually received — the standard set by the phone-number\n// validation in @wraps.dev/sms.\nconst EXPECTED_FORMAT =\n  'Expected an email address (e.g., user@example.com) or RFC 5322 form (e.g., \"Ada Lovelace\" <user@example.com>)';\n\n/**\n * Render what the caller actually passed, for the tail of an address error.\n * Objects are shown in full so a missing `email` key is visible rather than\n * echoing back an empty string.\n */\nfunction describeAddress(address: string | EmailAddress): string {\n  if (typeof address === 'string') {\n    // Quote blank input; an unquoted empty or whitespace-only value makes the\n    // error trail off into nothing.\n    return address.trim() === '' ? `\"${address}\" (blank)` : address;\n  }\n  return JSON.stringify(address);\n}\n\n/**\n * Extract email from RFC 5322 format strings like \"Name <email>\" or \"email\"\n */\nfunction extractEmail(address: string): string {\n  // Match email in angle brackets: \"Name <email>\" or just \"<email>\"\n  const angleMatch = address.match(/<([^>]+)>/);\n  if (angleMatch) {\n    return angleMatch[1].trim();\n  }\n\n  // No angle brackets - treat as plain email address\n  return address.trim();\n}\n\n/**\n * Basic email address validation using Zod\n * Zod's email validation is safer than custom regex patterns and avoids ReDoS vulnerabilities\n * Supports RFC 5322 format: \"Display Name <email@example.com>\" or plain \"email@example.com\"\n */\nfunction validateEmailAddress(address: string | EmailAddress, field: string): void {\n  // Reject CRLF in the full address string or in EmailAddress fields\n  if (typeof address === 'string') {\n    assertNoHeaderInjection(address, field);\n  } else {\n    assertNoHeaderInjection(address.email, field);\n    if (address.name) {\n      assertNoHeaderInjection(address.name, field);\n    }\n  }\n\n  // Extract email portion from string or EmailAddress object\n  const email = typeof address === 'string' ? extractEmail(address) : address.email;\n\n  if (!email) {\n    throw new ValidationError(\n      `Missing email address in field: ${field}. ${EXPECTED_FORMAT}, got: ${describeAddress(address)}`,\n      field\n    );\n  }\n\n  // Zod Mini email validator — tree-shakeable; avoids bundling all of zod at the\n  // edge. Behavior is identical to z.string().email() (verified). See plan 002.\n  const result = safeParse(zEmail(), email);\n\n  if (!result.success) {\n    throw new ValidationError(\n      `Invalid email format in field: ${field}. ${EXPECTED_FORMAT}, got: ${describeAddress(address)}`,\n      field\n    );\n  }\n}\n","import { AwsClient } from 'aws4fetch';\nimport { SESError, ValidationError } from './errors';\nimport type { EmailAddress, SendEmailParams, SendEmailResult } from './types';\nimport { htmlToPlainText } from './utils/html-to-text';\nimport {\n  normalizeEmailAddress,\n  normalizeEmailAddresses,\n  validateEmailParams,\n} from './utils/validation';\n\n/**\n * Static AWS credentials for edge environments.\n * Workers have no AWS credential chain, so region and credentials are required.\n */\nexport interface WrapsEmailWorkerConfig {\n  /** AWS region where your SES is configured (e.g. `'us-east-1'`). */\n  region: string;\n  /** Static AWS credentials. Store these as Wrangler secrets — never in source. */\n  credentials: {\n    accessKeyId: string;\n    secretAccessKey: string;\n    sessionToken?: string;\n  };\n  /**\n   * Custom SESv2 REST endpoint override. Defaults to the standard regional endpoint.\n   * Useful for local testing or custom domains.\n   */\n  endpoint?: string;\n}\n\n/**\n * `Omit` collapses a union into one object type, which would erase the\n * body-invariant branches of {@link SendEmailParams}. Distribute over the union\n * so each branch keeps its own shape.\n */\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\n/**\n * Subset of {@link SendEmailParams} supported at the edge.\n *\n * Not supported on the edge entry: `react` (render to HTML first),\n * `attachments` (MIME serialization requires Node built-ins),\n * `conversationId`, `sendId`, `replyTtlSeconds` (reply-threading uses SSM).\n *\n * `Extract` drops the `react` branch rather than omitting the field from it,\n * which would otherwise leave a branch with no body at all.\n */\nexport type WorkerSendEmailParams = DistributiveOmit<\n  Extract<SendEmailParams, { react?: never }>,\n  'react' | 'attachments' | 'conversationId' | 'sendId' | 'replyTtlSeconds'\n>;\n\n/**\n * Edge-native SES email client for Cloudflare Workers and other `workerd`-based runtimes.\n *\n * Uses `aws4fetch` (Web Crypto) to sign requests and the SESv2 REST API (JSON payloads,\n * no `DOMParser`) — zero Node.js APIs, ~5 KiB bundled.\n *\n * @example\n * ```typescript\n * const email = new WrapsEmail({\n *   region: env.AWS_REGION,\n *   credentials: {\n *     accessKeyId: env.AWS_ACCESS_KEY_ID,\n *     secretAccessKey: env.AWS_SECRET_ACCESS_KEY,\n *   },\n * });\n * const result = await email.send({\n *   from: 'hello@example.com',\n *   to: 'user@example.com',\n *   subject: 'Welcome!',\n *   html: '<h1>Hello</h1>',\n * });\n * ```\n */\nexport class WrapsEmail {\n  private readonly aws: AwsClient;\n  private readonly endpoint: string;\n\n  /**\n   * Create a new edge-native SES client.\n   *\n   * @param config - Region and static AWS credentials (required at the edge).\n   * @throws {ValidationError} If `region` or credentials fields are missing.\n   */\n  constructor(config: WrapsEmailWorkerConfig) {\n    if (!config?.region) {\n      throw new ValidationError('Missing required field: region', 'region');\n    }\n    if (!config?.credentials?.accessKeyId || !config?.credentials?.secretAccessKey) {\n      throw new ValidationError('Missing required field: credentials', 'credentials');\n    }\n    this.aws = new AwsClient({\n      accessKeyId: config.credentials.accessKeyId,\n      secretAccessKey: config.credentials.secretAccessKey,\n      sessionToken: config.credentials.sessionToken,\n      service: 'ses',\n      region: config.region,\n      retries: 0, // we handle errors ourselves; do not let aws4fetch retry\n    });\n    this.endpoint =\n      config.endpoint ?? `https://email.${config.region}.amazonaws.com/v2/email/outbound-emails`;\n  }\n\n  /**\n   * Send a single email via the SESv2 REST API.\n   *\n   * Mirrors the Node `WrapsEmail.send()` surface — change only the import path.\n   * When `html` is provided without `text`, plain text is auto-generated.\n   *\n   * @param params - Email send options. `react` and `attachments` are not supported at the edge.\n   * @returns Resolved with `{ messageId, requestId }` on success.\n   * @throws {ValidationError} If required fields are missing or unsupported options are used.\n   * @throws {SESError} If the SESv2 API returns a non-2xx response.\n   *\n   * @example\n   * ```typescript\n   * const result = await email.send({\n   *   from: 'hello@example.com',\n   *   to: ['alice@example.com', 'bob@example.com'],\n   *   subject: 'Hello!',\n   *   html: '<p>Hi there</p>',\n   * });\n   * console.log(result.messageId);\n   * ```\n   */\n  async send(params: WorkerSendEmailParams): Promise<SendEmailResult> {\n    const p = params as SendEmailParams;\n\n    if (p.react) {\n      throw new ValidationError(\n        'react is not supported at the edge; render to html first',\n        'react'\n      );\n    }\n    if (p.attachments && p.attachments.length > 0) {\n      throw new ValidationError('attachments are not supported at the edge', 'attachments');\n    }\n\n    validateEmailParams(p);\n\n    const payload = this.buildSesV2Payload(params);\n    const res = await this.aws.fetch(this.endpoint, {\n      method: 'POST',\n      headers: { 'content-type': 'application/json' },\n      body: JSON.stringify(payload),\n    });\n\n    if (!res.ok) {\n      throw await this.mapSesV2Error(res);\n    }\n\n    const requestId = res.headers.get('x-amzn-requestid') ?? 'unknown';\n    const body = (await res.json()) as { MessageId?: string };\n\n    if (!body.MessageId) {\n      throw new SESError(\n        'Invalid response from SES: missing MessageId',\n        'Unknown',\n        requestId,\n        false\n      );\n    }\n\n    return { messageId: body.MessageId, requestId };\n  }\n\n  private buildSesV2Payload(params: WorkerSendEmailParams): Record<string, unknown> {\n    let { html, text } = params;\n    if (html && !text) text = htmlToPlainText(html);\n\n    const body: Record<string, unknown> = {};\n    if (html) body.Html = { Data: html, Charset: 'UTF-8' };\n    if (text) body.Text = { Data: text, Charset: 'UTF-8' };\n\n    const payload: Record<string, unknown> = {\n      FromEmailAddress: normalizeEmailAddress(params.from),\n      Destination: {\n        ToAddresses: normalizeEmailAddresses(params.to),\n        ...(params.cc ? { CcAddresses: normalizeEmailAddresses(params.cc) } : {}),\n        ...(params.bcc ? { BccAddresses: normalizeEmailAddresses(params.bcc) } : {}),\n      },\n      ...(params.replyTo ? { ReplyToAddresses: normalizeEmailAddresses(params.replyTo) } : {}),\n      Content: {\n        Simple: {\n          Subject: { Data: params.subject, Charset: 'UTF-8' },\n          Body: body,\n        },\n      },\n      ...(params.tags\n        ? { EmailTags: Object.entries(params.tags).map(([Name, Value]) => ({ Name, Value })) }\n        : {}),\n      ...(params.configurationSetName ? { ConfigurationSetName: params.configurationSetName } : {}),\n    };\n\n    return payload;\n  }\n\n  private async mapSesV2Error(res: Response): Promise<SESError> {\n    const requestId = res.headers.get('x-amzn-requestid') ?? 'unknown';\n    const code = (res.headers.get('x-amzn-errortype') ?? 'Unknown').split(':')[0] || 'Unknown';\n\n    let message = 'SES request failed';\n    try {\n      const errBody = (await res.json()) as { message?: string; Message?: string };\n      message = errBody.message ?? errBody.Message ?? message;\n    } catch {\n      message = (await res.text().catch(() => '')) || message;\n    }\n\n    const retryable = res.status === 429 || res.status >= 500;\n    return new SESError(message, code, requestId, retryable);\n  }\n}\n\n// Re-export EmailAddress so callers can use it without a separate import\nexport type { EmailAddress };\n"]}