{"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\nexport class BatchError extends WrapsEmailError {\n  public readonly results: import('./types').BatchEntryResult[];\n  public readonly successCount: number;\n  public readonly failureCount: number;\n\n  constructor(\n    message: string,\n    results: import('./types').BatchEntryResult[],\n    successCount: number,\n    failureCount: number\n  ) {\n    super(message);\n    this.name = 'BatchError';\n    this.results = results;\n    this.successCount = successCount;\n    this.failureCount = failureCount;\n  }\n}\n\n/**\n * Map an AWS SDK v3 client error into a {@link SESError}. AWS SDK errors carry\n * `$metadata` (with `requestId`) and an optional `$retryable.throttling` flag.\n * Non-AWS errors 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 * @returns A `SESError` when the error looks like an AWS SDK error, else the\n *   original error.\n */\nexport function mapAwsSdkError(error: unknown, fallbackMessage = 'SES request failed'): Error {\n  const err = error as {\n    $metadata?: { requestId?: string };\n    $retryable?: { throttling?: boolean };\n    message?: string;\n    name?: string;\n  };\n  if (err.$metadata) {\n    return new SESError(\n      err.message || fallbackMessage,\n      err.name || 'Unknown',\n      err.$metadata.requestId || 'unknown',\n      err.$retryable?.throttling || false\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/**\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(`Invalid email address in field: ${field}`, field);\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(`Invalid email format in field: ${field} (${email})`, field);\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 * 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 */\nexport type WorkerSendEmailParams = Omit<\n  SendEmailParams,\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"]}