@wraps.dev/cli 1.5.2 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../node_modules/.pnpm/tsup@8.5.0_jiti@2.6.1_postcss@8.5.6_tsx@4.20.6_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js","../src/utils/shared/ci-detection.ts","../src/telemetry/config.ts","../package.json","../src/telemetry/client.ts","../src/telemetry/events.ts","../src/utils/shared/errors.ts","../src/utils/shared/aws.ts","../src/utils/email/route53.ts","../src/infrastructure/resources/acm.ts","../src/infrastructure/resources/cloudfront.ts","../src/infrastructure/resources/mail-manager.ts","../src/utils/email/costs.ts","../src/utils/email/presets.ts","../src/utils/shared/prompts.ts","../src/utils/shared/assume-role.ts","../src/utils/archive.ts","../src/console/services/email-archive.ts","../src/console/services/dynamodb-metrics.ts","../src/cli.ts","../src/commands/dashboard/update-role.ts","../src/utils/shared/metadata.ts","../src/utils/shared/fs.ts","../src/utils/shared/output.ts","../src/commands/email/config.ts","../src/infrastructure/email-stack.ts","../src/infrastructure/resources/dynamodb.ts","../src/infrastructure/resources/eventbridge.ts","../src/infrastructure/resources/iam.ts","../src/infrastructure/resources/lambda.ts","../src/infrastructure/resources/ses.ts","../src/infrastructure/resources/sqs.ts","../src/infrastructure/vercel-oidc.ts","../src/utils/shared/pulumi.ts","../src/commands/email/connect.ts","../src/utils/shared/scanner.ts","../src/commands/email/destroy.ts","../src/utils/route53.ts","../src/commands/email/domains.ts","../src/commands/email/init.ts","../src/commands/email/restore.ts","../src/commands/email/status.ts","../src/commands/email/upgrade.ts","../src/commands/shared/dashboard.ts","../src/console/server.ts","../src/console/middleware/auth.ts","../src/console/middleware/error.ts","../src/console/routes/domains.ts","../src/console/services/ses-service.ts","../src/console/routes/emails.ts","../src/console/services/email-logs.ts","../src/console/routes/metrics.ts","../src/console/services/aws-metrics.ts","../src/console/routes/settings.ts","../src/console/services/settings-service.ts","../src/console/routes/user.ts","../src/commands/shared/destroy.ts","../src/commands/shared/status.ts","../src/commands/telemetry.ts","../src/utils/shared/completion.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","/**\n * CI environment detection utilities\n * @module utils/shared/ci-detection\n */\n\n/**\n * Detect if running in CI environment\n *\n * Checks for common CI environment variables to determine\n * if the CLI is running in a continuous integration environment.\n *\n * @returns {boolean} True if running in CI, false otherwise\n *\n * @example\n * ```typescript\n * if (isCI()) {\n * console.log('Running in CI environment');\n * }\n * ```\n */\nexport function isCI(): boolean {\n // Universal CI indicator\n if (process.env.CI === \"true\" || process.env.CI === \"1\") {\n return true;\n }\n\n // Common CI providers\n const ciEnvVars = [\n \"GITHUB_ACTIONS\", // GitHub Actions\n \"GITLAB_CI\", // GitLab CI\n \"CIRCLECI\", // CircleCI\n \"TRAVIS\", // Travis CI\n \"JENKINS_URL\", // Jenkins\n \"BUILDKITE\", // Buildkite\n \"DRONE\", // Drone\n \"SEMAPHORE\", // Semaphore\n \"TEAMCITY_VERSION\", // TeamCity\n \"TF_BUILD\", // Azure Pipelines\n \"CODEBUILD_BUILD_ID\", // AWS CodeBuild\n \"NETLIFY\", // Netlify\n \"VERCEL\", // Vercel\n \"HEROKU_TEST_RUN_ID\", // Heroku CI\n \"BUDDY\", // Buddy\n \"BITBUCKET_BUILD_NUMBER\", // Bitbucket Pipelines\n ];\n\n return ciEnvVars.some((envVar) => process.env[envVar] !== undefined);\n}\n","/**\n * Telemetry configuration management\n * @module telemetry/config\n */\n\nimport Conf from \"conf\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport type { TelemetryConfig } from \"./types.js\";\n\nconst CONFIG_DEFAULTS: TelemetryConfig = {\n enabled: true,\n anonymousId: uuidv4(),\n notificationShown: false,\n};\n\n/**\n * Manages telemetry configuration stored locally\n *\n * Configuration is stored in platform-specific locations:\n * - macOS: ~/Library/Preferences/wraps/telemetry.json\n * - Linux: ~/.config/wraps/telemetry.json\n * - Windows: %APPDATA%\\wraps\\Config\\telemetry.json\n *\n * @example\n * ```typescript\n * const config = new TelemetryConfigManager();\n *\n * if (config.isEnabled()) {\n * console.log('Telemetry is enabled');\n * }\n *\n * config.setEnabled(false);\n * ```\n */\nexport class TelemetryConfigManager {\n private readonly config: Conf<TelemetryConfig>;\n\n constructor() {\n this.config = new Conf<TelemetryConfig>({\n projectName: \"wraps\",\n configName: \"telemetry\",\n defaults: CONFIG_DEFAULTS,\n });\n }\n\n /**\n * Check if telemetry is enabled\n */\n isEnabled(): boolean {\n return this.config.get(\"enabled\");\n }\n\n /**\n * Enable or disable telemetry\n */\n setEnabled(enabled: boolean): void {\n this.config.set(\"enabled\", enabled);\n }\n\n /**\n * Get the anonymous user ID\n */\n getAnonymousId(): string {\n return this.config.get(\"anonymousId\");\n }\n\n /**\n * Check if the first-run notification has been shown\n */\n hasShownNotification(): boolean {\n return this.config.get(\"notificationShown\");\n }\n\n /**\n * Mark the first-run notification as shown\n */\n markNotificationShown(): void {\n this.config.set(\"notificationShown\", true);\n }\n\n /**\n * Get the full path to the configuration file\n */\n getConfigPath(): string {\n return this.config.path;\n }\n\n /**\n * Reset configuration to defaults\n */\n reset(): void {\n this.config.clear();\n // Set new defaults with fresh UUID\n this.config.set({\n ...CONFIG_DEFAULTS,\n anonymousId: uuidv4(),\n });\n }\n}\n","{\n \"name\": \"@wraps.dev/cli\",\n \"version\": \"1.5.2\",\n \"description\": \"CLI for deploying Wraps email infrastructure to your AWS account\",\n \"type\": \"module\",\n \"main\": \"./dist/cli.js\",\n \"bin\": {\n \"wraps\": \"./dist/cli.js\"\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/wraps-team/wraps.git\",\n \"directory\": \"packages/cli\"\n },\n \"homepage\": \"https://wraps.dev\",\n \"bugs\": {\n \"url\": \"https://github.com/wraps-team/wraps/issues\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"dev\": \"tsup --watch\",\n \"build\": \"pnpm build:console && pnpm build:lambda && tsup\",\n \"build:lambda\": \"tsx scripts/build-lambda.ts\",\n \"build:console\": \"pnpm --filter @wraps/console build\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest --watch\",\n \"test:ui\": \"vitest --ui\",\n \"test:coverage\": \"vitest run --coverage\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"eslint src\",\n \"prepublishOnly\": \"pnpm build\"\n },\n \"keywords\": [\n \"aws\",\n \"ses\",\n \"email\",\n \"infrastructure\",\n \"cli\"\n ],\n \"author\": \"Wraps\",\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@aws-sdk/client-acm\": \"3.933.0\",\n \"@aws-sdk/client-cloudformation\": \"^3.490.0\",\n \"@aws-sdk/client-cloudfront\": \"3.933.0\",\n \"@aws-sdk/client-cloudwatch\": \"^3.490.0\",\n \"@aws-sdk/client-dynamodb\": \"^3.490.0\",\n \"@aws-sdk/client-iam\": \"3.932.0\",\n \"@aws-sdk/client-lambda\": \"3.925.0\",\n \"@aws-sdk/client-mailmanager\": \"3.925.0\",\n \"@aws-sdk/client-route-53\": \"3.925.0\",\n \"@aws-sdk/client-ses\": \"^3.490.0\",\n \"@aws-sdk/client-sesv2\": \"3.925.0\",\n \"@aws-sdk/client-sns\": \"^3.490.0\",\n \"@aws-sdk/client-sts\": \"^3.490.0\",\n \"@aws-sdk/util-dynamodb\": \"3.927.0\",\n \"@clack/prompts\": \"^0.11.0\",\n \"@pulumi/aws\": \"^7.11.1\",\n \"@pulumi/pulumi\": \"^3.207.0\",\n \"args\": \"^5.0.3\",\n \"conf\": \"^13.0.1\",\n \"cosmiconfig\": \"^9.0.0\",\n \"esbuild\": \"^0.25.12\",\n \"express\": \"^4.21.2\",\n \"get-port\": \"^7.1.0\",\n \"http-terminator\": \"^3.2.0\",\n \"isomorphic-dompurify\": \"2.32.0\",\n \"mailparser\": \"3.9.0\",\n \"open\": \"^10.1.0\",\n \"picocolors\": \"^1.1.1\",\n \"tabtab\": \"^3.0.2\",\n \"uuid\": \"^11.0.3\"\n },\n \"devDependencies\": {\n \"@types/args\": \"5.0.4\",\n \"@types/express\": \"^5.0.0\",\n \"@types/mailparser\": \"3.4.6\",\n \"@types/node\": \"^20.11.0\",\n \"@types/uuid\": \"^10.0.0\",\n \"@vitest/coverage-v8\": \"4.0.7\",\n \"aws-sdk-client-mock\": \"4.1.0\",\n \"aws-sdk-client-mock-vitest\": \"7.0.1\",\n \"eslint\": \"^8.56.0\",\n \"tsup\": \"^8.0.1\",\n \"tsx\": \"4.20.6\",\n \"typescript\": \"catalog:\",\n \"vitest\": \"^4.0.7\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n }\n}\n","/**\n * Telemetry client for Wraps CLI\n * @module telemetry/client\n */\n\nimport { isCI } from \"../utils/shared/ci-detection.js\";\nimport { TelemetryConfigManager } from \"./config.js\";\nimport type {\n TelemetryClientOptions,\n TelemetryEvent,\n TelemetryRequest,\n} from \"./types.js\";\n\nconst DEFAULT_ENDPOINT = \"https://wraps.dev/api/telemetry\";\nconst DEFAULT_TIMEOUT = 2000; // 2 seconds\n\n/**\n * Main telemetry client for tracking CLI usage\n *\n * Features:\n * - Non-blocking event tracking with automatic batching\n * - Respects DO_NOT_TRACK and WRAPS_TELEMETRY_DISABLED environment variables\n * - Auto-disabled in CI environments\n * - 2-second timeout with silent failure\n * - Debug mode for development\n *\n * @example\n * ```typescript\n * const client = getTelemetryClient();\n *\n * client.track('command:init', {\n * service: 'email',\n * success: true\n * });\n *\n * await client.shutdown(); // Flush remaining events\n * ```\n */\nexport class TelemetryClient {\n private readonly config: TelemetryConfigManager;\n private readonly endpoint: string;\n private readonly timeout: number;\n private readonly debug: boolean;\n private enabled: boolean;\n private eventQueue: TelemetryEvent[] = [];\n private flushTimer?: NodeJS.Timeout;\n\n constructor(options: TelemetryClientOptions = {}) {\n this.config = new TelemetryConfigManager();\n this.endpoint = options.endpoint || DEFAULT_ENDPOINT;\n this.timeout = options.timeout || DEFAULT_TIMEOUT;\n this.debug = options.debug || process.env.WRAPS_TELEMETRY_DEBUG === \"1\";\n\n // Check if telemetry should be enabled\n this.enabled = this.shouldBeEnabled();\n }\n\n /**\n * Determine if telemetry should be enabled based on environment and config\n */\n private shouldBeEnabled(): boolean {\n // Check DO_NOT_TRACK first (universal standard)\n if (process.env.DO_NOT_TRACK === \"1\") {\n return false;\n }\n\n // Check Wraps-specific env var\n if (process.env.WRAPS_TELEMETRY_DISABLED === \"1\") {\n return false;\n }\n\n // Check CI environment\n if (isCI()) {\n return false;\n }\n\n // Check config file\n if (!this.config.isEnabled()) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Track an event\n *\n * @param event - Event name in format \"category:action\" (e.g., \"command:init\")\n * @param properties - Additional event properties (no PII)\n */\n track(event: string, properties?: Record<string, unknown>): void {\n const telemetryEvent: TelemetryEvent = {\n event,\n properties: {\n ...properties,\n cli_version: this.getCLIVersion(),\n os: process.platform,\n node_version: process.version,\n ci: isCI(),\n },\n anonymousId: this.config.getAnonymousId(),\n timestamp: new Date().toISOString(),\n };\n\n // Debug mode: show what would be sent (even if disabled)\n if (this.debug) {\n console.log(\n \"[Telemetry Debug] Event:\",\n JSON.stringify(telemetryEvent, null, 2)\n );\n return;\n }\n\n // Check if telemetry is enabled (after debug check)\n if (!this.enabled) {\n return;\n }\n\n // Add to queue\n this.eventQueue.push(telemetryEvent);\n\n // Flush after short delay (batch events from same command)\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n }\n this.flushTimer = setTimeout(() => this.flush(), 100);\n }\n\n /**\n * Flush queued events to server\n */\n private async flush(): Promise<void> {\n if (this.eventQueue.length === 0) {\n return;\n }\n\n const eventsToSend = [...this.eventQueue];\n this.eventQueue = [];\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const requestBody: TelemetryRequest = {\n events: eventsToSend,\n batch: true,\n };\n\n await fetch(this.endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(requestBody),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n } catch (error) {\n // Silent failure - never break user's workflow\n if (this.debug) {\n console.error(\"[Telemetry Debug] Failed to send events:\", error);\n }\n }\n }\n\n /**\n * Flush and wait for all events to be sent\n * Should be called before CLI exits\n */\n async shutdown(): Promise<void> {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n }\n await this.flush();\n }\n\n /**\n * Enable telemetry\n * Note: Won't override environment variable opt-outs (DO_NOT_TRACK, CI, etc.)\n */\n enable(): void {\n this.config.setEnabled(true);\n\n // Check if environment variables prevent telemetry\n if (\n process.env.DO_NOT_TRACK === \"1\" ||\n process.env.DO_NOT_TRACK === \"true\"\n ) {\n this.enabled = false;\n return;\n }\n\n if (process.env.WRAPS_TELEMETRY_DISABLED === \"1\") {\n this.enabled = false;\n return;\n }\n\n if (isCI()) {\n this.enabled = false;\n return;\n }\n\n // No env restrictions, enable telemetry\n this.enabled = true;\n }\n\n /**\n * Disable telemetry\n */\n disable(): void {\n this.config.setEnabled(false);\n this.enabled = false;\n this.eventQueue = [];\n }\n\n /**\n * Check if telemetry is enabled\n */\n isEnabled(): boolean {\n return this.enabled;\n }\n\n /**\n * Get config file path\n */\n getConfigPath(): string {\n return this.config.getConfigPath();\n }\n\n /**\n * Show first-run notification\n */\n shouldShowNotification(): boolean {\n return this.enabled && !this.config.hasShownNotification();\n }\n\n /**\n * Mark notification as shown\n */\n markNotificationShown(): void {\n this.config.markNotificationShown();\n }\n\n /**\n * Get CLI version from package.json\n */\n private getCLIVersion(): string {\n try {\n // Dynamic import would be better but requires async\n // Using require for now since this is CommonJS compatible\n const packageJson = require(\"../../package.json\");\n return packageJson.version;\n } catch {\n return \"unknown\";\n }\n }\n}\n\n// Singleton instance\nlet telemetryInstance: TelemetryClient | null = null;\n\n/**\n * Get the singleton telemetry client instance\n *\n * @example\n * ```typescript\n * const client = getTelemetryClient();\n * client.track('command:init', { success: true });\n * ```\n */\nexport function getTelemetryClient(): TelemetryClient {\n if (!telemetryInstance) {\n telemetryInstance = new TelemetryClient();\n }\n return telemetryInstance;\n}\n","/**\n * Event tracking helpers for Wraps CLI\n * @module telemetry/events\n */\n\nimport { getTelemetryClient } from \"./client.js\";\n\n/**\n * Track CLI command execution\n *\n * @param command - Command name (e.g., \"email:init\", \"status\")\n * @param metadata - Additional metadata about command execution\n *\n * @example\n * ```typescript\n * trackCommand('email:init', {\n * success: true,\n * duration_ms: 1500,\n * preset: 'production'\n * });\n * ```\n */\nexport function trackCommand(\n command: string,\n metadata?: {\n success?: boolean;\n duration_ms?: number;\n preset?: string;\n provider?: string;\n service?: string;\n [key: string]: unknown;\n }\n): void {\n const client = getTelemetryClient();\n\n // Sanitize metadata to ensure no PII\n const sanitized = metadata ? { ...metadata } : {};\n\n // Remove any potentially sensitive fields\n sanitized.domain = undefined;\n sanitized.accountId = undefined;\n sanitized.email = undefined;\n\n client.track(`command:${command}`, sanitized);\n}\n\n/**\n * Track service initialization\n *\n * @param service - Service type (email, sms, etc.)\n * @param success - Whether initialization succeeded\n * @param metadata - Additional metadata\n *\n * @example\n * ```typescript\n * trackServiceInit('email', true, {\n * preset: 'production',\n * provider: 'vercel'\n * });\n * ```\n */\nexport function trackServiceInit(\n service: string,\n success: boolean,\n metadata?: {\n preset?: string;\n provider?: string;\n features?: string[];\n duration_ms?: number;\n [key: string]: unknown;\n }\n): void {\n const client = getTelemetryClient();\n\n client.track(\"service:init\", {\n service,\n success,\n ...metadata,\n });\n}\n\n/**\n * Track service deployment\n *\n * @param service - Service type (email, sms, etc.)\n * @param metadata - Deployment metadata\n *\n * @example\n * ```typescript\n * trackServiceDeployed('email', {\n * duration_ms: 45000,\n * features: ['tracking', 'history']\n * });\n * ```\n */\nexport function trackServiceDeployed(\n service: string,\n metadata?: {\n duration_ms?: number;\n features?: string[];\n preset?: string;\n [key: string]: unknown;\n }\n): void {\n const client = getTelemetryClient();\n\n client.track(\"service:deployed\", {\n service,\n ...metadata,\n });\n}\n\n/**\n * Track dashboard/console start\n *\n * @param mode - Console mode (local or hosted)\n * @param metadata - Additional metadata\n *\n * @example\n * ```typescript\n * trackConsoleStart('local', { port: 3100 });\n * ```\n */\nexport function trackConsoleStart(\n mode: \"local\" | \"hosted\",\n metadata?: Record<string, unknown>\n): void {\n const client = getTelemetryClient();\n\n client.track(\"console:started\", {\n mode,\n ...metadata,\n });\n}\n\n/**\n * Track console stop\n *\n * @param metadata - Stop metadata (e.g., duration)\n *\n * @example\n * ```typescript\n * trackConsoleStop({ duration_s: 300 });\n * ```\n */\nexport function trackConsoleStop(metadata?: {\n duration_s?: number;\n [key: string]: unknown;\n}): void {\n const client = getTelemetryClient();\n\n client.track(\"console:stopped\", metadata || {});\n}\n\n/**\n * Track error occurrence\n *\n * IMPORTANT: Never include error messages, only error codes\n * Error messages may contain sensitive information\n *\n * @param errorCode - Error code (e.g., \"AWS_CREDENTIALS_INVALID\")\n * @param command - Command where error occurred\n * @param metadata - Additional metadata\n *\n * @example\n * ```typescript\n * trackError('AWS_CREDENTIALS_INVALID', 'email:init', {\n * step: 'credential_validation'\n * });\n * ```\n */\nexport function trackError(\n errorCode: string,\n command: string,\n metadata?: Record<string, unknown>\n): void {\n const client = getTelemetryClient();\n\n client.track(\"error:occurred\", {\n error_code: errorCode,\n command,\n ...metadata,\n });\n}\n\n/**\n * Track feature usage\n *\n * @param feature - Feature name\n * @param metadata - Feature metadata\n *\n * @example\n * ```typescript\n * trackFeature('domain_verified', {\n * dns_provider: 'route53',\n * auto_detected: true\n * });\n * ```\n */\nexport function trackFeature(\n feature: string,\n metadata?: Record<string, unknown>\n): void {\n const client = getTelemetryClient();\n\n client.track(`feature:${feature}`, metadata || {});\n}\n\n/**\n * Track service upgrade\n *\n * @param service - Service type\n * @param metadata - Upgrade metadata\n *\n * @example\n * ```typescript\n * trackServiceUpgrade('email', {\n * from_preset: 'starter',\n * to_preset: 'production',\n * added_features: ['history', 'dedicated_ip']\n * });\n * ```\n */\nexport function trackServiceUpgrade(\n service: string,\n metadata?: {\n from_preset?: string;\n to_preset?: string;\n added_features?: string[];\n [key: string]: unknown;\n }\n): void {\n const client = getTelemetryClient();\n\n client.track(\"service:upgraded\", {\n service,\n ...metadata,\n });\n}\n\n/**\n * Track service removal\n *\n * @param service - Service type\n * @param metadata - Removal metadata\n *\n * @example\n * ```typescript\n * trackServiceRemoved('email', { reason: 'user_initiated' });\n * ```\n */\nexport function trackServiceRemoved(\n service: string,\n metadata?: Record<string, unknown>\n): void {\n const client = getTelemetryClient();\n\n client.track(\"service:removed\", {\n service,\n ...metadata,\n });\n}\n","import * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { trackError } from \"../../telemetry/events.js\";\n\n/**\n * Custom error class for Wraps CLI errors\n */\nexport class WrapsError extends Error {\n constructor(\n message: string,\n public code: string,\n public suggestion?: string,\n public docsUrl?: string\n ) {\n super(message);\n this.name = \"WrapsError\";\n }\n}\n\n/**\n * Global error handler for CLI errors\n * Formats and displays errors with suggestions and docs\n */\nexport function handleCLIError(error: unknown): never {\n console.error(\"\"); // Blank line\n\n if (error instanceof WrapsError) {\n // Track error (code only, never message)\n trackError(error.code, \"unknown\");\n\n clack.log.error(error.message);\n\n if (error.suggestion) {\n console.log(`\\n${pc.yellow(\"Suggestion:\")}`);\n console.log(` ${pc.white(error.suggestion)}\\n`);\n }\n\n if (error.docsUrl) {\n console.log(`${pc.dim(\"Documentation:\")}`);\n console.log(` ${pc.blue(error.docsUrl)}\\n`);\n }\n\n process.exit(1);\n }\n\n // Unknown error\n trackError(\"UNKNOWN_ERROR\", \"unknown\");\n\n clack.log.error(\"An unexpected error occurred\");\n console.error(error);\n console.log(`\\n${pc.dim(\"If this persists, please report at:\")}`);\n console.log(` ${pc.blue(\"https://github.com/wraps-team/wraps/issues\")}\\n`);\n process.exit(1);\n}\n\n/**\n * Common error factory functions\n */\nexport const errors = {\n noAWSCredentials: () =>\n new WrapsError(\n \"AWS credentials not found\",\n \"NO_AWS_CREDENTIALS\",\n \"Run: aws configure\\nOr set AWS_PROFILE environment variable\",\n \"https://wraps.dev/docs/setup/aws-credentials\"\n ),\n\n stackExists: (stackName: string) =>\n new WrapsError(\n `Stack \"${stackName}\" already exists`,\n \"STACK_EXISTS\",\n `To update: wraps email upgrade\\nTo remove: wraps destroy --stack ${stackName}`,\n \"https://wraps.dev/docs/cli/upgrade\"\n ),\n\n invalidRegion: (region: string) =>\n new WrapsError(\n `Invalid AWS region: ${region}`,\n \"INVALID_REGION\",\n \"Use a valid AWS region like: us-east-1, eu-west-1, ap-southeast-1\",\n \"https://docs.aws.amazon.com/general/latest/gr/rande.html\"\n ),\n\n pulumiError: (message: string) =>\n new WrapsError(\n `Infrastructure deployment failed: ${message}`,\n \"PULUMI_ERROR\",\n \"Check your AWS permissions and try again\",\n \"https://wraps.dev/docs/troubleshooting\"\n ),\n\n noStack: () =>\n new WrapsError(\n \"No Wraps infrastructure found in this AWS account\",\n \"NO_STACK\",\n \"Run: wraps email init\\nTo deploy new infrastructure\",\n \"https://wraps.dev/docs/cli/init\"\n ),\n\n pulumiNotInstalled: () =>\n new WrapsError(\n \"Pulumi CLI is not installed\",\n \"PULUMI_NOT_INSTALLED\",\n \"Install Pulumi:\\n macOS: brew install pulumi/tap/pulumi\\n Linux: curl -fsSL https://get.pulumi.com | sh\\n Windows: choco install pulumi\\n\\nOr download from: https://www.pulumi.com/docs/install/\",\n \"https://www.pulumi.com/docs/install/\"\n ),\n\n stackLocked: () =>\n new WrapsError(\n \"The Pulumi stack is locked from a previous run\",\n \"STACK_LOCKED\",\n \"This happens when a previous deployment was interrupted.\\n\\nTo unlock, run:\\n rm -rf ~/.wraps/pulumi/.pulumi/locks\\n\\nThen try your command again.\",\n \"https://wraps.dev/docs/troubleshooting\"\n ),\n};\n","import { ACMClient, DescribeCertificateCommand } from \"@aws-sdk/client-acm\";\nimport {\n GetIdentityVerificationAttributesCommand,\n ListIdentitiesCommand,\n SESClient,\n} from \"@aws-sdk/client-ses\";\nimport { GetCallerIdentityCommand, STSClient } from \"@aws-sdk/client-sts\";\nimport { errors } from \"./errors.js\";\n\n/**\n * AWS identity information\n */\nexport type AWSIdentity = {\n accountId: string;\n userId: string;\n arn: string;\n};\n\n/**\n * Validate AWS credentials by calling STS GetCallerIdentity\n */\nexport async function validateAWSCredentials(): Promise<AWSIdentity> {\n const sts = new STSClient({ region: \"us-east-1\" });\n\n try {\n const identity = await sts.send(new GetCallerIdentityCommand({}));\n return {\n accountId: identity.Account!,\n userId: identity.UserId!,\n arn: identity.Arn!,\n };\n } catch (_error) {\n throw errors.noAWSCredentials();\n }\n}\n\n/**\n * Check if a region is valid\n */\nexport async function checkRegion(region: string): Promise<boolean> {\n // List of valid AWS regions (as of 2025)\n const validRegions = [\n \"us-east-1\",\n \"us-east-2\",\n \"us-west-1\",\n \"us-west-2\",\n \"af-south-1\",\n \"ap-east-1\",\n \"ap-south-1\",\n \"ap-northeast-1\",\n \"ap-northeast-2\",\n \"ap-northeast-3\",\n \"ap-southeast-1\",\n \"ap-southeast-2\",\n \"ap-southeast-3\",\n \"ca-central-1\",\n \"eu-central-1\",\n \"eu-west-1\",\n \"eu-west-2\",\n \"eu-west-3\",\n \"eu-south-1\",\n \"eu-north-1\",\n \"me-south-1\",\n \"sa-east-1\",\n ];\n\n return validRegions.includes(region);\n}\n\n/**\n * Get AWS region from environment or config\n */\nexport async function getAWSRegion(): Promise<string> {\n // Try to detect region from various sources\n if (process.env.AWS_REGION) {\n return process.env.AWS_REGION;\n }\n if (process.env.AWS_DEFAULT_REGION) {\n return process.env.AWS_DEFAULT_REGION;\n }\n\n // Default fallback\n return \"us-east-1\";\n}\n\n/**\n * SES domain identity\n */\nexport type SESDomain = {\n domain: string;\n verified: boolean;\n};\n\n/**\n * List all SES identities (domains) in the account\n */\nexport async function listSESDomains(region: string): Promise<SESDomain[]> {\n const ses = new SESClient({ region });\n\n try {\n // Get all identities\n const identitiesResponse = await ses.send(\n new ListIdentitiesCommand({\n IdentityType: \"Domain\",\n })\n );\n\n const identities = identitiesResponse.Identities || [];\n\n if (identities.length === 0) {\n return [];\n }\n\n // Get verification attributes\n const attributesResponse = await ses.send(\n new GetIdentityVerificationAttributesCommand({\n Identities: identities,\n })\n );\n\n const attributes = attributesResponse.VerificationAttributes || {};\n\n // Map to SESDomain objects\n return identities.map((domain) => ({\n domain,\n verified: attributes[domain]?.VerificationStatus === \"Success\",\n }));\n } catch (error) {\n console.error(\"Error listing SES domains:\", error);\n return [];\n }\n}\n\n/**\n * Check if SES is in sandbox mode\n */\nexport async function isSESSandbox(region: string): Promise<boolean> {\n const ses = new SESClient({ region });\n\n try {\n // In sandbox mode, you can only send to verified addresses\n // This is a heuristic - we check if there are any identities\n await ses.send(\n new ListIdentitiesCommand({\n MaxItems: 1,\n })\n );\n\n // If we can call this API, SES is enabled\n // The actual sandbox check requires checking send quota\n // For now, we'll return false (not sandbox) if the API works\n return false;\n } catch (error: any) {\n // If we get an error about SES not being enabled, return true\n if (error.name === \"InvalidParameterValue\") {\n return true;\n }\n throw error;\n }\n}\n\n/**\n * ACM certificate status\n */\nexport type ACMCertificateStatus = {\n status: string;\n domainName: string;\n validationRecords: Array<{\n name: string;\n type: string;\n value: string;\n }>;\n};\n\n/**\n * Check ACM certificate validation status\n * Note: ACM certificates for CloudFront must be in us-east-1\n */\nexport async function getACMCertificateStatus(\n certificateArn: string\n): Promise<ACMCertificateStatus | null> {\n const acm = new ACMClient({ region: \"us-east-1\" });\n\n try {\n const response = await acm.send(\n new DescribeCertificateCommand({\n CertificateArn: certificateArn,\n })\n );\n\n const certificate = response.Certificate;\n if (!certificate) {\n return null;\n }\n\n // Extract validation records\n const validationRecords =\n certificate.DomainValidationOptions?.map((option) => ({\n name: option.ResourceRecord?.Name || \"\",\n type: option.ResourceRecord?.Type || \"\",\n value: option.ResourceRecord?.Value || \"\",\n })) || [];\n\n return {\n status: certificate.Status || \"UNKNOWN\",\n domainName: certificate.DomainName || \"\",\n validationRecords,\n };\n } catch (error) {\n console.error(\"Error getting ACM certificate status:\", error);\n return null;\n }\n}\n","import {\n type Change,\n ChangeResourceRecordSetsCommand,\n ListHostedZonesByNameCommand,\n Route53Client,\n} from \"@aws-sdk/client-route-53\";\n\n/**\n * Find Route53 hosted zone for a domain\n *\n * This function searches for a hosted zone that matches the given domain.\n * It will try the exact domain first, then fall back to parent domains.\n * For example, if given \"track.example.com\", it will check:\n * 1. track.example.com\n * 2. example.com\n */\nexport async function findHostedZone(\n domain: string,\n region: string\n): Promise<{ id: string; name: string } | null> {\n const client = new Route53Client({ region });\n\n // Try exact domain first\n try {\n const response = await client.send(\n new ListHostedZonesByNameCommand({\n DNSName: domain,\n MaxItems: 1,\n })\n );\n\n const zone = response.HostedZones?.[0];\n if (zone && zone.Name === `${domain}.` && zone.Id) {\n return {\n id: zone.Id.replace(\"/hostedzone/\", \"\"),\n name: zone.Name,\n };\n }\n } catch (_error) {\n // Continue to try parent domains\n }\n\n // Try parent domains (e.g., track.example.com -> example.com)\n const parts = domain.split(\".\");\n if (parts.length > 2) {\n const parentDomain = parts.slice(1).join(\".\");\n return findHostedZone(parentDomain, region);\n }\n\n return null;\n}\n\n/**\n * Create DNS records in Route53\n */\nexport async function createDNSRecords(\n hostedZoneId: string,\n domain: string,\n dkimTokens: string[],\n region: string,\n customTrackingDomain?: string,\n mailFromDomain?: string,\n cloudFrontDomain?: string\n): Promise<void> {\n const client = new Route53Client({ region });\n\n const changes: Change[] = [];\n\n // DKIM CNAME records\n for (const token of dkimTokens) {\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: `${token}._domainkey.${domain}`,\n Type: \"CNAME\",\n TTL: 1800,\n ResourceRecords: [{ Value: `${token}.dkim.amazonses.com` }],\n },\n });\n }\n\n // SPF TXT record\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: domain,\n Type: \"TXT\",\n TTL: 1800,\n ResourceRecords: [{ Value: '\"v=spf1 include:amazonses.com ~all\"' }],\n },\n });\n\n // DMARC TXT record\n // If MAIL FROM domain is provided, use it for the reporting address (rua)\n // Otherwise, use the main domain\n const dmarcReportEmail = mailFromDomain\n ? `postmaster@${mailFromDomain}`\n : `postmaster@${domain}`;\n\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: `_dmarc.${domain}`,\n Type: \"TXT\",\n TTL: 1800,\n ResourceRecords: [\n { Value: `\"v=DMARC1; p=quarantine; rua=mailto:${dmarcReportEmail}\"` },\n ],\n },\n });\n\n // Custom tracking domain CNAME (if provided)\n // This allows SES to rewrite links for open/click tracking using your custom domain\n if (customTrackingDomain) {\n // If CloudFront domain is provided, use it (HTTPS tracking)\n // Otherwise, use direct SES tracking endpoint (HTTP tracking)\n const targetDomain = cloudFrontDomain || `r.${region}.awstrack.me`;\n\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: customTrackingDomain,\n Type: \"CNAME\",\n TTL: 1800,\n ResourceRecords: [{ Value: targetDomain }],\n },\n });\n }\n\n // MAIL FROM domain records (if provided)\n // These records enable DMARC alignment by using a custom subdomain for the envelope sender\n if (mailFromDomain) {\n // MX record pointing to SES feedback server\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: mailFromDomain,\n Type: \"MX\",\n TTL: 1800,\n ResourceRecords: [\n { Value: `10 feedback-smtp.${region}.amazonses.com` },\n ],\n },\n });\n\n // SPF record for MAIL FROM domain\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: mailFromDomain,\n Type: \"TXT\",\n TTL: 1800,\n ResourceRecords: [{ Value: '\"v=spf1 include:amazonses.com ~all\"' }],\n },\n });\n }\n\n await client.send(\n new ChangeResourceRecordSetsCommand({\n HostedZoneId: hostedZoneId,\n ChangeBatch: {\n Changes: changes,\n },\n })\n );\n}\n","import * as aws from \"@pulumi/aws\";\nimport type * as pulumi from \"@pulumi/pulumi\";\n\n/**\n * ACM certificate configuration\n */\nexport type ACMCertificateConfig = {\n domain: string;\n hostedZoneId?: string; // Optional Route53 hosted zone for automatic DNS validation\n};\n\n/**\n * ACM certificate output\n */\nexport type ACMCertificateResources = {\n certificate: aws.acm.Certificate;\n certificateValidation?: aws.acm.CertificateValidation;\n validationRecords: pulumi.Output<\n Array<{\n name: string;\n type: string;\n value: string;\n }>\n >;\n};\n\n/**\n * Create ACM certificate for custom tracking domain\n *\n * IMPORTANT: CloudFront requires ACM certificates to be created in us-east-1 region.\n * This function creates the certificate in us-east-1 regardless of the SES region.\n *\n * If a Route53 hosted zone ID is provided, DNS validation records will be created\n * automatically and we'll wait for validation. Otherwise, validation records are\n * returned for manual creation.\n */\nexport async function createACMCertificate(\n config: ACMCertificateConfig\n): Promise<ACMCertificateResources> {\n const usEast1Provider = new aws.Provider(\"acm-us-east-1\", {\n region: \"us-east-1\",\n });\n\n // Create ACM certificate in us-east-1 (required for CloudFront)\n const certificate = new aws.acm.Certificate(\n \"wraps-email-tracking-cert\",\n {\n domainName: config.domain,\n validationMethod: \"DNS\",\n tags: {\n ManagedBy: \"wraps-cli\",\n Description: \"SSL certificate for Wraps email tracking domain\",\n },\n },\n {\n provider: usEast1Provider,\n }\n );\n\n // Extract validation records\n const validationRecords = certificate.domainValidationOptions.apply(\n (options) =>\n options.map((option) => ({\n name: option.resourceRecordName,\n type: option.resourceRecordType,\n value: option.resourceRecordValue,\n }))\n );\n\n // If Route53 hosted zone is provided, create validation records automatically\n let certificateValidation: aws.acm.CertificateValidation | undefined;\n\n if (config.hostedZoneId) {\n // Create validation record in Route53\n const validationRecord = new aws.route53.Record(\n \"wraps-email-tracking-cert-validation\",\n {\n zoneId: config.hostedZoneId,\n name: certificate.domainValidationOptions[0].resourceRecordName,\n type: certificate.domainValidationOptions[0].resourceRecordType,\n records: [certificate.domainValidationOptions[0].resourceRecordValue],\n ttl: 60,\n }\n );\n\n // Wait for certificate validation to complete\n certificateValidation = new aws.acm.CertificateValidation(\n \"wraps-email-tracking-cert-validation-waiter\",\n {\n certificateArn: certificate.arn,\n validationRecordFqdns: [validationRecord.fqdn],\n },\n {\n provider: usEast1Provider,\n }\n );\n }\n // For manual DNS: certificateValidation is undefined\n // User must add DNS records manually and run upgrade again\n\n return {\n certificate,\n certificateValidation,\n validationRecords,\n };\n}\n","import * as aws from \"@pulumi/aws\";\nimport type * as pulumi from \"@pulumi/pulumi\";\n\n/**\n * CloudFront resources configuration\n */\nexport type CloudFrontTrackingConfig = {\n customTrackingDomain: string;\n region: string; // SES region for the origin\n certificateArn: pulumi.Output<string>;\n hostedZoneId?: string; // Optional Route53 hosted zone for automatic DNS record creation\n};\n\n/**\n * Find existing CloudFront distribution by alias (CNAME)\n */\nasync function findDistributionByAlias(alias: string): Promise<string | null> {\n try {\n const { CloudFrontClient, ListDistributionsCommand } = await import(\n \"@aws-sdk/client-cloudfront\"\n );\n const cloudfront = new CloudFrontClient({ region: \"us-east-1\" }); // CloudFront is global but API is in us-east-1\n\n const response = await cloudfront.send(new ListDistributionsCommand({}));\n\n // Find distribution with matching alias\n const distribution = response.DistributionList?.Items?.find((dist) =>\n dist.Aliases?.Items?.includes(alias)\n );\n\n return distribution?.Id || null;\n } catch (error) {\n console.error(\"Error finding CloudFront distribution:\", error);\n return null;\n }\n}\n\n/**\n * CloudFront resources output\n */\nexport type CloudFrontResources = {\n distribution: aws.cloudfront.Distribution;\n domainName: pulumi.Output<string>;\n webAcl: aws.wafv2.WebAcl;\n};\n\n/**\n * Create WAF Web ACL with rate limiting for CloudFront\n *\n * This creates a WAFv2 Web ACL with rate limiting protection\n * to prevent abuse of tracking endpoints.\n */\nasync function createWAFWebACL(): Promise<aws.wafv2.WebAcl> {\n // WAF for CloudFront must be created in us-east-1\n const usEast1Provider = new aws.Provider(\"waf-us-east-1\", {\n region: \"us-east-1\",\n });\n\n const webAcl = new aws.wafv2.WebAcl(\n \"wraps-email-tracking-waf\",\n {\n scope: \"CLOUDFRONT\", // WAF for CloudFront must use CLOUDFRONT scope\n description: \"Rate limiting protection for Wraps email tracking\",\n\n defaultAction: {\n allow: {}, // Allow by default\n },\n\n rules: [\n {\n name: \"RateLimitRule\",\n priority: 1,\n action: {\n block: {}, // Block requests exceeding rate limit\n },\n statement: {\n rateBasedStatement: {\n limit: 2000, // 2000 requests per 5 minutes per IP\n aggregateKeyType: \"IP\",\n },\n },\n visibilityConfig: {\n sampledRequestsEnabled: true,\n cloudwatchMetricsEnabled: true,\n metricName: \"RateLimitRule\",\n },\n },\n ],\n\n visibilityConfig: {\n sampledRequestsEnabled: true,\n cloudwatchMetricsEnabled: true,\n metricName: \"wraps-email-tracking-waf\",\n },\n\n tags: {\n ManagedBy: \"wraps-cli\",\n Description: \"WAF for Wraps email tracking with rate limiting\",\n },\n },\n {\n provider: usEast1Provider,\n }\n );\n\n return webAcl;\n}\n\n/**\n * Create CloudFront distribution for HTTPS tracking domain\n *\n * This creates a CloudFront distribution that sits in front of AWS SES's tracking endpoint\n * (r.{region}.awstrack.me) and provides HTTPS support with a custom domain and SSL certificate.\n * Also creates a WAF Web ACL with rate limiting for security.\n */\nexport async function createCloudFrontTracking(\n config: CloudFrontTrackingConfig\n): Promise<CloudFrontResources> {\n const sesTrackingOrigin = `r.${config.region}.awstrack.me`;\n\n // Create WAF Web ACL with rate limiting protection\n const webAcl = await createWAFWebACL();\n\n // Check if CloudFront distribution already exists with this alias\n const existingDistributionId = await findDistributionByAlias(\n config.customTrackingDomain\n );\n\n // CloudFront distribution configuration\n const distributionConfig = {\n enabled: true,\n comment: \"Wraps email tracking with HTTPS support\",\n aliases: [config.customTrackingDomain],\n\n // Attach WAF Web ACL for rate limiting protection\n webAclId: webAcl.arn,\n\n // Origin: SES tracking endpoint\n origins: [\n {\n domainName: sesTrackingOrigin,\n originId: \"ses-tracking\",\n customOriginConfig: {\n httpPort: 80,\n httpsPort: 443,\n originProtocolPolicy: \"http-only\", // SES tracking endpoint is HTTP\n originSslProtocols: [\"TLSv1.2\"],\n },\n },\n ],\n\n // Default cache behavior\n defaultCacheBehavior: {\n targetOriginId: \"ses-tracking\",\n viewerProtocolPolicy: \"redirect-to-https\", // Force HTTPS\n allowedMethods: [\"GET\", \"HEAD\", \"OPTIONS\"],\n cachedMethods: [\"GET\", \"HEAD\"],\n\n // Forward all query strings and headers (tracking links use query params)\n forwardedValues: {\n queryString: true,\n cookies: {\n forward: \"all\",\n },\n headers: [\"*\"], // Forward all headers to preserve tracking functionality\n },\n\n // Minimal caching for tracking redirects\n minTtl: 0,\n defaultTtl: 0,\n maxTtl: 31_536_000,\n\n compress: true,\n },\n\n // Price class (use only North America & Europe for cost optimization)\n priceClass: \"PriceClass_100\",\n\n // Restrictions (none)\n restrictions: {\n geoRestriction: {\n restrictionType: \"none\",\n },\n },\n\n // SSL certificate from ACM\n viewerCertificate: {\n acmCertificateArn: config.certificateArn,\n sslSupportMethod: \"sni-only\",\n minimumProtocolVersion: \"TLSv1.2_2021\",\n },\n\n tags: {\n ManagedBy: \"wraps-cli\",\n Description: \"Wraps email tracking CloudFront distribution\",\n },\n };\n\n const distribution = existingDistributionId\n ? new aws.cloudfront.Distribution(\n \"wraps-email-tracking-cdn\",\n distributionConfig,\n {\n import: existingDistributionId, // Import existing distribution\n }\n )\n : new aws.cloudfront.Distribution(\n \"wraps-email-tracking-cdn\",\n distributionConfig\n );\n\n // Note: DNS CNAME record for custom tracking domain is created separately\n // via Route53 SDK in route53.ts (using UPSERT for idempotency)\n // This prevents Pulumi resource conflicts on subsequent deployments\n\n return {\n distribution,\n domainName: distribution.domainName,\n webAcl,\n };\n}\n","import {\n CreateArchiveCommand,\n GetArchiveCommand,\n ListArchivesCommand,\n MailManagerClient,\n type RetentionPeriod,\n} from \"@aws-sdk/client-mailmanager\";\nimport {\n PutConfigurationSetArchivingOptionsCommand,\n SESv2Client,\n} from \"@aws-sdk/client-sesv2\";\nimport type * as pulumi from \"@pulumi/pulumi\";\nimport type { ArchiveRetention } from \"../../types/index.js\";\n\n/**\n * Mail Manager archive configuration\n */\nexport type MailManagerArchiveConfig = {\n name: string;\n retention: ArchiveRetention;\n configSetName: pulumi.Output<string>;\n region?: string;\n kmsKeyArn?: string; // Optional: provide existing KMS key, otherwise AWS-managed key is used\n};\n\n/**\n * Mail Manager archive resources\n */\nexport type MailManagerArchiveResources = {\n archiveId: string;\n archiveArn: string;\n kmsKeyArn?: string;\n};\n\n/**\n * Convert our retention types to AWS SDK RetentionPeriod enum\n */\nfunction retentionToAWSPeriod(retention: ArchiveRetention): RetentionPeriod {\n switch (retention) {\n case \"3months\":\n return \"THREE_MONTHS\";\n case \"6months\":\n return \"SIX_MONTHS\";\n case \"9months\":\n return \"NINE_MONTHS\";\n case \"1year\":\n return \"ONE_YEAR\";\n case \"18months\":\n return \"EIGHTEEN_MONTHS\";\n case \"2years\":\n return \"TWO_YEARS\";\n case \"30months\":\n return \"THIRTY_MONTHS\";\n case \"3years\":\n return \"THREE_YEARS\";\n case \"4years\":\n return \"FOUR_YEARS\";\n case \"5years\":\n return \"FIVE_YEARS\";\n case \"6years\":\n return \"SIX_YEARS\";\n case \"7years\":\n return \"SEVEN_YEARS\";\n case \"8years\":\n return \"EIGHT_YEARS\";\n case \"9years\":\n return \"NINE_YEARS\";\n case \"10years\":\n return \"TEN_YEARS\";\n case \"permanent\":\n return \"PERMANENT\";\n default:\n return \"THREE_MONTHS\";\n }\n}\n\n/**\n * Create Mail Manager archive for storing full email content\n *\n * This creates:\n * 1. Mail Manager Archive - stores RFC 822/MIME formatted emails\n * 2. Links archive to SES Configuration Set\n *\n * Uses AWS SDK directly since Pulumi doesn't support Mail Manager yet.\n *\n * Cost: $2/GB ingestion + $0.19/GB/month storage\n * See: https://docs.aws.amazon.com/ses/latest/dg/eb-archiving.html\n *\n * Note: KMS encryption is optional. If not provided, AWS-managed encryption is used.\n */\nexport async function createMailManagerArchive(\n config: MailManagerArchiveConfig\n): Promise<MailManagerArchiveResources> {\n const region = config.region || process.env.AWS_REGION || \"us-east-1\";\n const archiveName = `wraps-${config.name}-archive`;\n\n // Initialize clients\n const mailManagerClient = new MailManagerClient({ region });\n const sesClient = new SESv2Client({ region });\n\n const kmsKeyArn = config.kmsKeyArn;\n\n // If no KMS key provided, create one for encryption\n // Note: User can also opt to not provide one and AWS will use service-managed keys\n if (!kmsKeyArn) {\n // For now, we'll let AWS use service-managed keys\n // In the future, we could create a customer-managed key here if needed:\n //\n // const kmsClient = new KMSClient({ region });\n // const createKeyResult = await kmsClient.send(\n // new CreateKeyCommand({\n // Description: `KMS key for Wraps email archive (${archiveName})`,\n // Tags: [\n // { TagKey: \"ManagedBy\", TagValue: \"wraps-cli\" },\n // { TagKey: \"Name\", TagValue: `wraps-${config.name}-archive-key` },\n // ],\n // })\n // );\n // kmsKeyArn = createKeyResult.KeyMetadata?.Arn;\n }\n\n // 1. Create Mail Manager Archive (or get existing)\n const awsRetention = retentionToAWSPeriod(config.retention);\n\n let archiveId: string | undefined;\n let archiveArn: string | undefined;\n\n // Check if archive already exists\n try {\n const listCommand = new ListArchivesCommand({});\n const listResult = await mailManagerClient.send(listCommand);\n\n const existingArchive = listResult.Archives?.find(\n (archive: { ArchiveName?: string; ArchiveId?: string }) =>\n archive.ArchiveName === archiveName\n );\n\n if (existingArchive?.ArchiveId) {\n // Archive exists, use it\n console.log(`Using existing Mail Manager archive: ${archiveName}`);\n archiveId = existingArchive.ArchiveId;\n\n // Get full archive details to get ARN\n const getCommand = new GetArchiveCommand({ ArchiveId: archiveId });\n const getResult = await mailManagerClient.send(getCommand);\n archiveArn = getResult.ArchiveArn;\n }\n } catch (error) {\n console.log(\"Error checking for existing archive:\", error);\n // Continue to create new archive\n }\n\n // Create archive if it doesn't exist\n if (!archiveId) {\n try {\n const createArchiveCommand = new CreateArchiveCommand({\n ArchiveName: archiveName,\n Retention: {\n RetentionPeriod: awsRetention,\n },\n ...(kmsKeyArn && { KmsKeyArn: kmsKeyArn }),\n Tags: [\n { Key: \"ManagedBy\", Value: \"wraps-cli\" },\n { Key: \"Name\", Value: archiveName },\n { Key: \"Retention\", Value: config.retention },\n ],\n });\n\n const archiveResult = await mailManagerClient.send(createArchiveCommand);\n archiveId = archiveResult.ArchiveId;\n\n if (!archiveId) {\n throw new Error(\n \"Failed to create Mail Manager Archive: No ArchiveId returned\"\n );\n }\n\n console.log(`Created new Mail Manager archive: ${archiveName}`);\n } catch (error) {\n // If it's a ConflictException, the archive was created between our check and now\n if (\n error instanceof Error &&\n error.name === \"ConflictException\" &&\n error.message.includes(\"Archive already exists\")\n ) {\n console.log(\n \"Archive was created concurrently, fetching existing archive...\"\n );\n\n // List again and find it\n const listCommand = new ListArchivesCommand({});\n const listResult = await mailManagerClient.send(listCommand);\n const existingArchive = listResult.Archives?.find(\n (archive: { ArchiveName?: string; ArchiveId?: string }) =>\n archive.ArchiveName === archiveName\n );\n\n if (!existingArchive?.ArchiveId) {\n throw new Error(\n `Archive exists but couldn't find it: ${archiveName}`\n );\n }\n\n archiveId = existingArchive.ArchiveId;\n\n // Get full archive details\n const getCommand = new GetArchiveCommand({ ArchiveId: archiveId });\n const getResult = await mailManagerClient.send(getCommand);\n archiveArn = getResult.ArchiveArn;\n } else {\n throw error;\n }\n }\n }\n\n // Construct the ARN if we don't have it yet\n if (!archiveArn) {\n // ARN format: arn:aws:ses:region:account-id:mailmanager-archive/archive-id\n const identity = await import(\"@aws-sdk/client-sts\").then((m) =>\n new m.STSClient({ region }).send(new m.GetCallerIdentityCommand({}))\n );\n const accountId = identity.Account;\n archiveArn = `arn:aws:ses:${region}:${accountId}:mailmanager-archive/${archiveId}`;\n }\n\n // 2. Link archive to SES Configuration Set\n // We need to wait for the configSetName to resolve from Pulumi Output\n const configSetName = await new Promise<string>((resolve) => {\n config.configSetName.apply((name) => {\n resolve(name);\n });\n });\n\n const putArchivingOptionsCommand =\n new PutConfigurationSetArchivingOptionsCommand({\n ConfigurationSetName: configSetName,\n ArchiveArn: archiveArn,\n });\n\n await sesClient.send(putArchivingOptionsCommand);\n\n if (!(archiveId && archiveArn)) {\n throw new Error(\"Failed to get archive ID or ARN\");\n }\n\n return {\n archiveId,\n archiveArn,\n kmsKeyArn,\n };\n}\n","import type {\n ArchiveRetention,\n FeatureCost,\n FeatureCostBreakdown,\n WrapsEmailConfig,\n} from \"../../types/index.js\";\n\n/**\n * AWS pricing constants (as of 2025)\n * All costs in USD (US East N. Virginia region)\n * Source: aws.amazon.com pricing pages verified January 2025\n */\nconst AWS_PRICING = {\n // SES pricing\n SES_PER_EMAIL: 0.0001, // $0.10 per 1,000 emails (outbound)\n SES_ATTACHMENT_PER_GB: 0.12, // $0.12 per GB of attachments\n\n // DynamoDB pricing (on-demand, Standard table class)\n DYNAMODB_WRITE_PER_MILLION: 1.25, // $1.25 per million write request units (US East Ohio)\n DYNAMODB_READ_PER_MILLION: 0.25, // $0.25 per million read request units (US East Ohio)\n DYNAMODB_STORAGE_PER_GB: 0.25, // $0.25 per GB-month\n\n // Lambda pricing (x86)\n LAMBDA_REQUESTS_PER_MILLION: 0.2, // $0.20 per 1M requests\n LAMBDA_COMPUTE_PER_GB_SECOND: 0.000_016_666_7, // $0.0000166667 per GB-second\n\n // SQS pricing (Standard queues)\n SQS_REQUESTS_PER_MILLION: 0.5, // $0.50 per million requests (after free tier)\n\n // EventBridge pricing\n EVENTBRIDGE_EVENTS_PER_MILLION: 1.0, // $1.00 per million custom events published\n\n // Dedicated IP\n DEDICATED_IP_PER_MONTH: 24.95, // $24.95 per dedicated IP per month\n\n // CloudWatch pricing\n CLOUDWATCH_LOGS_PER_GB: 0.5, // $0.50 per GB ingested\n CLOUDWATCH_LOGS_STORAGE_PER_GB: 0.03, // $0.03 per GB-month\n\n // SES Mail Manager Archiving\n MAIL_MANAGER_INGESTION_PER_GB: 2.0, // $2.00 per GB ingested\n MAIL_MANAGER_STORAGE_PER_GB: 0.19, // $0.19 per GB-month\n} as const;\n\n/**\n * AWS Free tier limits (monthly, always-free or first 12 months)\n * Note: Some limits are permanently free, others only for first 12 months\n */\nconst FREE_TIER = {\n // SES: 3,000 emails/month for first 12 months (new AWS accounts only)\n // After 12 months or for existing accounts: NO free tier\n SES_EMAILS: 0, // Conservative: assume no free tier (most users are past 12 months)\n\n // Lambda: Permanently free tier\n LAMBDA_REQUESTS: 1_000_000, // 1M requests per month (always free)\n LAMBDA_COMPUTE_GB_SECONDS: 400_000, // 400,000 GB-seconds per month (always free)\n\n // DynamoDB: Permanently free tier\n DYNAMODB_WRITES: 0, // No free tier for writes in on-demand mode\n DYNAMODB_READS: 0, // No free tier for reads in on-demand mode\n DYNAMODB_STORAGE_GB: 25, // 25 GB storage per month (always free)\n\n // SQS: Permanently free tier\n SQS_REQUESTS: 1_000_000, // 1M requests per month (always free)\n\n // CloudWatch: Permanently free tier\n CLOUDWATCH_LOGS_GB: 5, // 5 GB ingestion per month (always free)\n} as const;\n\n/**\n * Estimate storage size in GB based on retention period and email volume\n * Note: Each email generates multiple events (SEND, DELIVERY, OPEN, CLICK, etc.)\n *\n * This calculates STEADY-STATE storage (after retention period fills up).\n * Initial months will be cheaper as storage builds up gradually.\n *\n * Example for 90-day retention with 10k emails/month:\n * - Month 1: ~0.015 GB stored\n * - Month 2: ~0.031 GB stored\n * - Month 3: ~0.046 GB stored (steady state reached)\n * - Month 4+: ~0.046 GB stored (old data deleted, new data added)\n */\nfunction estimateStorageSize(\n emailsPerMonth: number,\n retention: ArchiveRetention,\n numEventTypes = 8\n): number {\n // Average email event record size: ~2 KB (including metadata)\n const avgRecordSizeKB = 2;\n\n // Calculate total months of retention\n const retentionMonths = {\n \"7days\": 0.25,\n \"30days\": 1,\n \"90days\": 3,\n \"3months\": 3,\n \"6months\": 6,\n \"9months\": 9,\n \"1year\": 12,\n \"18months\": 18,\n \"2years\": 24,\n \"30months\": 30,\n \"3years\": 36,\n \"4years\": 48,\n \"5years\": 60,\n \"6years\": 72,\n \"7years\": 84,\n \"8years\": 96,\n \"9years\": 108,\n \"10years\": 120,\n indefinite: 120,\n permanent: 120,\n }[retention];\n\n // Total steady-state storage = emails/month * event types * months * record size\n // This represents storage after retention period fills up\n const totalKB =\n emailsPerMonth * numEventTypes * (retentionMonths ?? 12) * avgRecordSizeKB;\n return totalKB / 1024 / 1024; // Convert to GB\n}\n\n/**\n * Estimate email archive storage size in GB (for full email content)\n * Different from event storage - stores complete RFC 822/MIME emails\n *\n * This calculates STEADY-STATE storage (after retention period fills up).\n */\nfunction estimateArchiveStorageSize(\n emailsPerMonth: number,\n retention: ArchiveRetention\n): number {\n // Average full email size: ~50 KB (HTML, headers, small attachments)\n const avgEmailSizeKB = 50;\n\n // Calculate total months of retention\n const retentionMonths = {\n \"7days\": 0.25,\n \"30days\": 1,\n \"90days\": 3,\n \"3months\": 3,\n \"6months\": 6,\n \"9months\": 9,\n \"1year\": 12,\n \"18months\": 18,\n \"2years\": 24,\n \"30months\": 30,\n \"3years\": 36,\n \"4years\": 48,\n \"5years\": 60,\n \"6years\": 72,\n \"7years\": 84,\n \"8years\": 96,\n \"9years\": 108,\n \"10years\": 120,\n indefinite: 120,\n permanent: 120,\n }[retention];\n\n // Total steady-state storage = emails/month * months * email size\n const totalKB = emailsPerMonth * (retentionMonths ?? 12) * avgEmailSizeKB;\n return totalKB / 1024 / 1024; // Convert to GB\n}\n\n/**\n * Calculate cost for event tracking feature\n * Architecture: SES → EventBridge → SQS → Lambda → DynamoDB\n */\nfunction calculateEventTrackingCost(\n config: WrapsEmailConfig,\n emailsPerMonth: number\n): FeatureCost | undefined {\n if (!config.eventTracking?.enabled) {\n return;\n }\n\n let monthlyCost = 0;\n const components: string[] = [];\n\n // Calculate number of events based on event types tracked\n const numEventTypes = config.eventTracking.events?.length || 8; // Default to 8 common events\n const totalEvents = emailsPerMonth * numEventTypes; // Each email can trigger multiple events\n\n // EventBridge custom events (SES → EventBridge)\n if (config.eventTracking.eventBridge) {\n const eventCost =\n (totalEvents / 1_000_000) * AWS_PRICING.EVENTBRIDGE_EVENTS_PER_MILLION;\n monthlyCost += eventCost;\n components.push(\"EventBridge\");\n }\n\n // SQS queue costs (EventBridge → SQS)\n // Each event: 1 send to SQS + 1 receive by Lambda + 1 delete = 3 requests\n const sqsRequests = totalEvents * 3;\n const sqsCost =\n (Math.max(0, sqsRequests - FREE_TIER.SQS_REQUESTS) / 1_000_000) *\n AWS_PRICING.SQS_REQUESTS_PER_MILLION;\n monthlyCost += sqsCost;\n components.push(\"SQS\");\n\n // Lambda processing costs (SQS → Lambda → DynamoDB)\n const lambdaInvocations = totalEvents; // One invocation per event\n const lambdaRequestCost =\n (Math.max(0, lambdaInvocations - FREE_TIER.LAMBDA_REQUESTS) / 1_000_000) *\n AWS_PRICING.LAMBDA_REQUESTS_PER_MILLION;\n\n // Compute cost: 512MB memory, 100ms average execution\n const memoryGB = 0.5; // 512MB = 0.5GB\n const avgDurationSeconds = 0.1; // 100ms\n const computeGBSeconds = lambdaInvocations * memoryGB * avgDurationSeconds;\n const lambdaComputeCost =\n Math.max(0, computeGBSeconds - FREE_TIER.LAMBDA_COMPUTE_GB_SECONDS) *\n AWS_PRICING.LAMBDA_COMPUTE_PER_GB_SECOND;\n\n monthlyCost += lambdaRequestCost + lambdaComputeCost;\n components.push(\"Lambda\");\n\n return {\n monthly: monthlyCost,\n description: `Event processing (${numEventTypes} event types: ${components.join(\" → \")})`,\n };\n}\n\n/**\n * Calculate cost for DynamoDB email history storage\n */\nfunction calculateDynamoDBCost(\n config: WrapsEmailConfig,\n emailsPerMonth: number\n): FeatureCost | undefined {\n if (!config.eventTracking?.dynamoDBHistory) {\n return;\n }\n\n const retention = config.eventTracking.archiveRetention || \"90days\";\n const numEventTypes = config.eventTracking.events?.length || 8;\n\n // Write costs: one write per event (each email generates multiple events)\n const totalEvents = emailsPerMonth * numEventTypes;\n const writeCost =\n (Math.max(0, totalEvents - FREE_TIER.DYNAMODB_WRITES) / 1_000_000) *\n AWS_PRICING.DYNAMODB_WRITE_PER_MILLION;\n\n // Storage costs\n const storageGB = estimateStorageSize(\n emailsPerMonth,\n retention,\n numEventTypes\n );\n const storageCost =\n Math.max(0, storageGB - FREE_TIER.DYNAMODB_STORAGE_GB) *\n AWS_PRICING.DYNAMODB_STORAGE_PER_GB;\n\n return {\n monthly: writeCost + storageCost,\n description: `Email history (${retention}, ~${storageGB.toFixed(2)} GB at steady-state, ${numEventTypes} event types)`,\n };\n}\n\n/**\n * Calculate cost for tracking features (opens/clicks)\n */\nfunction calculateTrackingCost(\n config: WrapsEmailConfig\n): FeatureCost | undefined {\n if (!config.tracking?.enabled) {\n return;\n }\n\n // Tracking is free - it's built into SES\n // Custom redirect domain DNS records are managed where user already manages DNS\n return {\n monthly: 0,\n description: \"Open/click tracking (no additional cost)\",\n };\n}\n\n/**\n * Calculate cost for reputation metrics\n */\nfunction calculateReputationMetricsCost(\n config: WrapsEmailConfig\n): FeatureCost | undefined {\n if (!config.reputationMetrics) {\n return;\n }\n\n // Reputation metrics are free in CloudWatch\n return {\n monthly: 0,\n description: \"Reputation metrics in CloudWatch (no additional cost)\",\n };\n}\n\n/**\n * Calculate cost for dedicated IP\n */\nfunction calculateDedicatedIpCost(\n config: WrapsEmailConfig\n): FeatureCost | undefined {\n if (!config.dedicatedIp) {\n return;\n }\n\n return {\n monthly: AWS_PRICING.DEDICATED_IP_PER_MONTH,\n description: \"Dedicated IP address (requires 100k+ emails/day for warmup)\",\n };\n}\n\n/**\n * Calculate cost for email archiving (full email content storage)\n * Architecture: SES → Mail Manager Archive (S3-backed)\n */\nfunction calculateEmailArchivingCost(\n config: WrapsEmailConfig,\n emailsPerMonth: number\n): FeatureCost | undefined {\n if (!config.emailArchiving?.enabled) {\n return;\n }\n\n const retention = config.emailArchiving.retention;\n const storageGB = estimateArchiveStorageSize(emailsPerMonth, retention);\n\n // Ingestion cost: one-time per email (charged monthly as new emails arrive)\n const monthlyDataGB = (emailsPerMonth * 50) / 1024 / 1024; // 50 KB average email\n const ingestionCost =\n monthlyDataGB * AWS_PRICING.MAIL_MANAGER_INGESTION_PER_GB;\n\n // Storage cost: steady-state storage after retention period fills\n const storageCost = storageGB * AWS_PRICING.MAIL_MANAGER_STORAGE_PER_GB;\n\n return {\n monthly: ingestionCost + storageCost,\n description: `Email archiving (${retention}, ~${storageGB.toFixed(2)} GB at steady-state)`,\n };\n}\n\n/**\n * Calculate total infrastructure costs\n *\n * @param config Email configuration\n * @param emailsPerMonth Estimated monthly email volume\n * @returns Detailed cost breakdown\n */\nexport function calculateCosts(\n config: WrapsEmailConfig,\n emailsPerMonth = 10_000\n): FeatureCostBreakdown {\n const tracking = calculateTrackingCost(config);\n const reputationMetrics = calculateReputationMetricsCost(config);\n const eventTracking = calculateEventTrackingCost(config, emailsPerMonth);\n const dynamoDBHistory = calculateDynamoDBCost(config, emailsPerMonth);\n const emailArchiving = calculateEmailArchivingCost(config, emailsPerMonth);\n const dedicatedIp = calculateDedicatedIpCost(config);\n\n // Calculate SES base costs (always present)\n const sesEmailCost =\n Math.max(0, emailsPerMonth - FREE_TIER.SES_EMAILS) *\n AWS_PRICING.SES_PER_EMAIL;\n\n // Sum all costs\n const totalMonthlyCost =\n sesEmailCost +\n (tracking?.monthly || 0) +\n (reputationMetrics?.monthly || 0) +\n (eventTracking?.monthly || 0) +\n (dynamoDBHistory?.monthly || 0) +\n (emailArchiving?.monthly || 0) +\n (dedicatedIp?.monthly || 0);\n\n return {\n tracking,\n reputationMetrics,\n eventTracking,\n dynamoDBHistory,\n emailArchiving,\n dedicatedIp,\n total: {\n monthly: totalMonthlyCost,\n perEmail: AWS_PRICING.SES_PER_EMAIL,\n description: `Total estimated cost for ${emailsPerMonth.toLocaleString()} emails/month`,\n },\n };\n}\n\n/**\n * Format cost for display\n */\nexport function formatCost(cost: number): string {\n if (cost === 0) {\n return \"Free\";\n }\n if (cost < 0.01) {\n return \"< $0.01\";\n }\n return `$${cost.toFixed(2)}`;\n}\n\n/**\n * Get cost estimate summary for display\n */\nexport function getCostSummary(\n config: WrapsEmailConfig,\n emailsPerMonth = 10_000\n): string {\n const costs = calculateCosts(config, emailsPerMonth);\n const lines: string[] = [];\n\n lines.push(\n `Estimated cost for ${emailsPerMonth.toLocaleString()} emails/month: ${formatCost(costs.total.monthly)}/mo`\n );\n lines.push(\n ` (${formatCost((costs.total.perEmail ?? 0) * 1000)}/1k emails + infrastructure)`\n );\n\n if (costs.tracking) {\n lines.push(\n ` - ${costs.tracking.description}: ${formatCost(costs.tracking.monthly)}`\n );\n }\n if (costs.reputationMetrics) {\n lines.push(\n ` - ${costs.reputationMetrics.description}: ${formatCost(costs.reputationMetrics.monthly)}`\n );\n }\n if (costs.eventTracking) {\n lines.push(\n ` - ${costs.eventTracking.description}: ${formatCost(costs.eventTracking.monthly)}`\n );\n }\n if (costs.dynamoDBHistory) {\n lines.push(\n ` - ${costs.dynamoDBHistory.description}: ${formatCost(costs.dynamoDBHistory.monthly)}`\n );\n }\n if (costs.emailArchiving) {\n lines.push(\n ` - ${costs.emailArchiving.description}: ${formatCost(costs.emailArchiving.monthly)}`\n );\n }\n if (costs.dedicatedIp) {\n lines.push(\n ` - ${costs.dedicatedIp.description}: ${formatCost(costs.dedicatedIp.monthly)}`\n );\n }\n\n return lines.join(\"\\n\");\n}\n","import type { ConfigPreset, WrapsEmailConfig } from \"../../types/index.js\";\nimport { calculateCosts, formatCost } from \"./costs.js\";\n\n/**\n * Preset configurations with recommended settings for different use cases\n */\n\n/**\n * Starter preset - minimal features for low-volume senders\n * Perfect for: Side projects, MVPs, development/staging\n * Volume: Up to 10k emails/month\n * Cost: ~$1-2/month (without archiving)\n */\nexport const STARTER_PRESET: WrapsEmailConfig = {\n tracking: {\n enabled: true,\n opens: true,\n clicks: true,\n },\n tlsRequired: true,\n reputationMetrics: false,\n suppressionList: {\n enabled: true,\n reasons: [\"BOUNCE\", \"COMPLAINT\"],\n },\n eventTracking: {\n enabled: false,\n },\n // Email archiving disabled by default\n emailArchiving: {\n enabled: false,\n retention: \"30days\",\n },\n sendingEnabled: true,\n};\n\n/**\n * Production preset - recommended for most production applications\n * Perfect for: SaaS apps, B2B products, moderate volume\n * Volume: 10k-500k emails/month\n * Cost: ~$10-50/month (scales with volume, add ~$5-15/mo for archiving)\n */\nexport const PRODUCTION_PRESET: WrapsEmailConfig = {\n tracking: {\n enabled: true,\n opens: true,\n clicks: true,\n },\n tlsRequired: true,\n reputationMetrics: true,\n suppressionList: {\n enabled: true,\n reasons: [\"BOUNCE\", \"COMPLAINT\"],\n },\n eventTracking: {\n enabled: true,\n eventBridge: true,\n events: [\n \"SEND\",\n \"DELIVERY\",\n \"OPEN\",\n \"CLICK\",\n \"BOUNCE\",\n \"COMPLAINT\",\n \"REJECT\",\n \"RENDERING_FAILURE\",\n ],\n dynamoDBHistory: true,\n archiveRetention: \"90days\",\n },\n // Email archiving with 90-day retention\n emailArchiving: {\n enabled: false, // User can opt-in\n retention: \"90days\",\n },\n sendingEnabled: true,\n};\n\n/**\n * Enterprise preset - full features for high-volume senders\n * Perfect for: Large platforms, high-volume transactional email\n * Volume: 500k+ emails/month\n * Cost: ~$100-200/month (includes $24.95 dedicated IP, add ~$50+/mo for archiving)\n */\nexport const ENTERPRISE_PRESET: WrapsEmailConfig = {\n tracking: {\n enabled: true,\n opens: true,\n clicks: true,\n },\n tlsRequired: true,\n reputationMetrics: true,\n suppressionList: {\n enabled: true,\n reasons: [\"BOUNCE\", \"COMPLAINT\"],\n },\n eventTracking: {\n enabled: true,\n eventBridge: true,\n events: [\n \"SEND\",\n \"DELIVERY\",\n \"OPEN\",\n \"CLICK\",\n \"BOUNCE\",\n \"COMPLAINT\",\n \"REJECT\",\n \"RENDERING_FAILURE\",\n \"DELIVERY_DELAY\",\n \"SUBSCRIPTION\",\n ],\n dynamoDBHistory: true,\n archiveRetention: \"1year\",\n },\n // Email archiving with 1-year retention\n emailArchiving: {\n enabled: false, // User can opt-in\n retention: \"1year\",\n },\n dedicatedIp: true,\n sendingEnabled: true,\n};\n\n/**\n * Get preset configuration by name\n */\nexport function getPreset(preset: ConfigPreset): WrapsEmailConfig | null {\n switch (preset) {\n case \"starter\":\n return STARTER_PRESET;\n case \"production\":\n return PRODUCTION_PRESET;\n case \"enterprise\":\n return ENTERPRISE_PRESET;\n case \"custom\":\n return null; // User will configure manually\n }\n}\n\n/**\n * Preset metadata for display\n */\nexport type PresetInfo = {\n name: string;\n description: string;\n recommended: string;\n volume: string;\n estimatedCost: string;\n features: string[];\n};\n\n/**\n * Get preset information for display\n */\nexport function getPresetInfo(preset: ConfigPreset): PresetInfo {\n const config = getPreset(preset);\n\n if (preset === \"custom\" || !config) {\n return {\n name: \"Custom\",\n description: \"Configure each feature individually\",\n recommended: \"Advanced users who need specific configuration\",\n volume: \"Any volume\",\n estimatedCost: \"Varies\",\n features: [\"Full control over all features\"],\n };\n }\n\n const costs = calculateCosts(\n config,\n preset === \"starter\"\n ? 10_000\n : preset === \"production\"\n ? 100_000\n : 1_000_000\n );\n\n const baseInfo = {\n starter: {\n name: \"Starter\",\n description: \"Minimal features for low-volume senders\",\n recommended: \"Side projects, MVPs, development/staging\",\n volume: \"Up to 10k emails/month\",\n features: [\n \"Open & click tracking\",\n \"TLS encryption required\",\n \"Automatic bounce/complaint suppression\",\n \"Optional: Email archiving (full content storage)\",\n ],\n },\n production: {\n name: \"Production\",\n description: \"Recommended for most production applications\",\n recommended: \"SaaS apps, B2B products, moderate volume (RECOMMENDED)\",\n volume: \"10k-500k emails/month\",\n features: [\n \"Everything in Starter\",\n \"Reputation tracking\",\n \"Real-time event tracking (EventBridge)\",\n \"90-day email history storage\",\n \"Optional: Email archiving with rendered viewer\",\n \"Complete event visibility\",\n ],\n },\n enterprise: {\n name: \"Enterprise\",\n description: \"Full features for high-volume senders\",\n recommended: \"Large platforms, high-volume transactional email\",\n volume: \"500k+ emails/month\",\n features: [\n \"Everything in Production\",\n \"Dedicated IP address\",\n \"1-year email history\",\n \"Optional: 1-year+ email archiving\",\n \"All event types tracked\",\n \"Priority support eligibility\",\n ],\n },\n }[preset];\n\n return {\n ...baseInfo,\n estimatedCost: formatCost(costs.total.monthly),\n } as PresetInfo;\n}\n\n/**\n * Get all preset options for CLI prompts\n */\nexport function getAllPresetInfo(): PresetInfo[] {\n return [\n getPresetInfo(\"starter\"),\n getPresetInfo(\"production\"),\n getPresetInfo(\"enterprise\"),\n getPresetInfo(\"custom\"),\n ];\n}\n\n/**\n * Compare two configurations to determine upgrade path\n */\nexport function getUpgradePath(\n current: WrapsEmailConfig,\n target: WrapsEmailConfig\n): string[] {\n const changes: string[] = [];\n\n // Check tracking changes\n if (!current.tracking?.enabled && target.tracking?.enabled) {\n changes.push(\"Enable email tracking (opens & clicks)\");\n }\n\n // Check reputation metrics\n if (!current.reputationMetrics && target.reputationMetrics) {\n changes.push(\"Enable reputation metrics\");\n }\n\n // Check event tracking\n if (!current.eventTracking?.enabled && target.eventTracking?.enabled) {\n changes.push(\"Enable real-time event tracking\");\n }\n\n // Check DynamoDB history\n if (\n !current.eventTracking?.dynamoDBHistory &&\n target.eventTracking?.dynamoDBHistory\n ) {\n changes.push(\"Enable email history storage\");\n }\n\n // Check retention upgrade\n if (\n current.eventTracking?.archiveRetention !==\n target.eventTracking?.archiveRetention &&\n target.eventTracking?.archiveRetention\n ) {\n changes.push(\n `Upgrade retention: ${current.eventTracking?.archiveRetention || \"none\"} → ${target.eventTracking.archiveRetention}`\n );\n }\n\n // Check dedicated IP\n if (!current.dedicatedIp && target.dedicatedIp) {\n changes.push(\"Add dedicated IP address\");\n }\n\n return changes;\n}\n\n/**\n * Validate configuration for common issues\n */\nexport function validateConfig(config: WrapsEmailConfig): string[] {\n const warnings: string[] = [];\n\n // Warn about dedicated IP without high volume\n if (config.dedicatedIp) {\n warnings.push(\n \"⚠️ Dedicated IPs require 100k+ emails/day for proper warmup. Consider starting with shared IPs.\"\n );\n }\n\n // Warn about event tracking without storage\n if (config.eventTracking?.enabled && !config.eventTracking?.dynamoDBHistory) {\n warnings.push(\n \"💡 Event tracking is enabled but history storage is disabled. Events will only be available in real-time.\"\n );\n }\n\n // Warn about long retention without need\n if (config.eventTracking?.archiveRetention === \"indefinite\") {\n warnings.push(\n \"⚠️ Indefinite retention can become expensive. Consider 90-day or 1-year retention.\"\n );\n }\n\n return warnings;\n}\n","import * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport type { ArchiveRetention } from \"../../types/index.js\";\n\n/**\n * Hosting provider type\n */\nexport type Provider = \"vercel\" | \"aws\" | \"railway\" | \"other\";\n\n/**\n * Prompt for hosting provider\n */\nexport async function promptProvider(): Promise<Provider> {\n const provider = await clack.select({\n message: \"Where is your app hosted?\",\n options: [\n {\n value: \"aws\",\n label: \"AWS (Lambda/ECS/EC2)\",\n hint: \"Uses IAM roles automatically\",\n },\n {\n value: \"vercel\",\n label: \"Vercel\",\n hint: \"Uses OIDC (no AWS credentials needed)\",\n },\n {\n value: \"railway\",\n label: \"Railway\",\n hint: \"Requires AWS credentials\",\n },\n {\n value: \"other\",\n label: \"Other\",\n hint: \"Will use AWS access keys\",\n },\n ],\n });\n\n if (clack.isCancel(provider)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return provider as Provider;\n}\n\n/**\n * Prompt for AWS region\n */\nexport async function promptRegion(defaultRegion: string): Promise<string> {\n const region = await clack.select({\n message: \"Select AWS region:\",\n options: [\n { value: \"us-east-1\", label: \"US East (N. Virginia)\", hint: \"us-east-1\" },\n { value: \"us-east-2\", label: \"US East (Ohio)\", hint: \"us-east-2\" },\n {\n value: \"us-west-1\",\n label: \"US West (N. California)\",\n hint: \"us-west-1\",\n },\n { value: \"us-west-2\", label: \"US West (Oregon)\", hint: \"us-west-2\" },\n { value: \"af-south-1\", label: \"Africa (Cape Town)\", hint: \"af-south-1\" },\n {\n value: \"ap-east-1\",\n label: \"Asia Pacific (Hong Kong)\",\n hint: \"ap-east-1\",\n },\n {\n value: \"ap-south-1\",\n label: \"Asia Pacific (Mumbai)\",\n hint: \"ap-south-1\",\n },\n {\n value: \"ap-northeast-1\",\n label: \"Asia Pacific (Tokyo)\",\n hint: \"ap-northeast-1\",\n },\n {\n value: \"ap-northeast-2\",\n label: \"Asia Pacific (Seoul)\",\n hint: \"ap-northeast-2\",\n },\n {\n value: \"ap-northeast-3\",\n label: \"Asia Pacific (Osaka)\",\n hint: \"ap-northeast-3\",\n },\n {\n value: \"ap-southeast-1\",\n label: \"Asia Pacific (Singapore)\",\n hint: \"ap-southeast-1\",\n },\n {\n value: \"ap-southeast-2\",\n label: \"Asia Pacific (Sydney)\",\n hint: \"ap-southeast-2\",\n },\n {\n value: \"ap-southeast-3\",\n label: \"Asia Pacific (Jakarta)\",\n hint: \"ap-southeast-3\",\n },\n {\n value: \"ca-central-1\",\n label: \"Canada (Central)\",\n hint: \"ca-central-1\",\n },\n {\n value: \"eu-central-1\",\n label: \"Europe (Frankfurt)\",\n hint: \"eu-central-1\",\n },\n { value: \"eu-west-1\", label: \"Europe (Ireland)\", hint: \"eu-west-1\" },\n { value: \"eu-west-2\", label: \"Europe (London)\", hint: \"eu-west-2\" },\n { value: \"eu-west-3\", label: \"Europe (Paris)\", hint: \"eu-west-3\" },\n { value: \"eu-south-1\", label: \"Europe (Milan)\", hint: \"eu-south-1\" },\n { value: \"eu-north-1\", label: \"Europe (Stockholm)\", hint: \"eu-north-1\" },\n {\n value: \"me-south-1\",\n label: \"Middle East (Bahrain)\",\n hint: \"me-south-1\",\n },\n {\n value: \"sa-east-1\",\n label: \"South America (São Paulo)\",\n hint: \"sa-east-1\",\n },\n ],\n initialValue: defaultRegion || \"us-east-1\",\n });\n\n if (clack.isCancel(region)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return region as string;\n}\n\n/**\n * Prompt for domain to verify (optional)\n */\nexport async function promptDomain(): Promise<string> {\n const domain = await clack.text({\n message: \"Domain to verify (optional):\",\n placeholder: \"myapp.com\",\n validate: (value) => {\n if (!value) {\n return; // Optional\n }\n if (!value.includes(\".\")) {\n return \"Please enter a valid domain (e.g., myapp.com)\";\n }\n },\n });\n\n if (clack.isCancel(domain)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return domain || \"\";\n}\n\n/**\n * Vercel configuration\n */\nexport type VercelConfig = {\n teamSlug: string;\n projectName: string;\n};\n\n/**\n * Prompt for Vercel configuration\n */\nexport async function promptVercelConfig(): Promise<VercelConfig> {\n const config = await clack.group(\n {\n teamSlug: () =>\n clack.text({\n message: \"Vercel team slug:\",\n placeholder: \"my-team\",\n validate: (value) => {\n if (!value) {\n return \"Team slug is required for Vercel integration\";\n }\n },\n }),\n projectName: () =>\n clack.text({\n message: \"Vercel project name:\",\n placeholder: \"my-project\",\n validate: (value) => {\n if (!value) {\n return \"Project name is required\";\n }\n },\n }),\n },\n {\n onCancel: () => {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n },\n }\n );\n\n return config as VercelConfig;\n}\n\n/**\n * Prompt for integration level\n */\nexport async function promptIntegrationLevel(): Promise<\n \"dashboard-only\" | \"enhanced\"\n> {\n const level = await clack.select({\n message: \"Integration level:\",\n options: [\n {\n value: \"enhanced\",\n label: \"Enhanced (full email tracking)\",\n hint: \"Creates SES config, DynamoDB, Lambda functions\",\n },\n {\n value: \"dashboard-only\",\n label: \"Dashboard-only (read-only)\",\n hint: \"Only creates IAM role for dashboard access\",\n },\n ],\n });\n\n if (clack.isCancel(level)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return level as \"dashboard-only\" | \"enhanced\";\n}\n\n/**\n * Confirm deployment\n */\nexport async function confirmDeploy(): Promise<boolean> {\n const confirmed = await clack.confirm({\n message: \"Deploy infrastructure to your AWS account?\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirmed)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return confirmed;\n}\n\n/**\n * Feature definition for multi-select\n */\nexport type FeatureOption = {\n value: string;\n label: string;\n hint: string;\n};\n\n/**\n * Get available features\n */\nexport function getAvailableFeatures(): FeatureOption[] {\n return [\n {\n value: \"configSet\",\n label: \"Configuration Set\",\n hint: \"Track opens, clicks, bounces, and complaints\",\n },\n {\n value: \"bounceHandling\",\n label: \"Bounce Handling\",\n hint: \"Automatically process bounce notifications\",\n },\n {\n value: \"complaintHandling\",\n label: \"Complaint Handling\",\n hint: \"Automatically process spam complaints\",\n },\n {\n value: \"emailHistory\",\n label: \"Email History\",\n hint: \"Store sent emails in DynamoDB (90-day retention)\",\n },\n {\n value: \"eventProcessor\",\n label: \"Event Processor\",\n hint: \"Advanced analytics and webhook forwarding\",\n },\n {\n value: \"dashboardAccess\",\n label: \"Dashboard Access\",\n hint: \"Read-only IAM role for web dashboard\",\n },\n ];\n}\n\n/**\n * Prompt for feature selection (multi-select)\n */\nexport async function promptFeatureSelection(\n preselected?: string[]\n): Promise<string[]> {\n const features = getAvailableFeatures();\n\n const selected = await clack.multiselect({\n message: \"Select features to deploy:\",\n options: features,\n initialValues: preselected || [\n \"configSet\",\n \"bounceHandling\",\n \"complaintHandling\",\n \"dashboardAccess\",\n ],\n required: true,\n });\n\n if (clack.isCancel(selected)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return selected as string[];\n}\n\n/**\n * Conflict resolution action\n */\nexport type ConflictAction = \"deploy-alongside\" | \"replace\" | \"skip\";\n\n/**\n * Prompt for conflict resolution\n */\nexport async function promptConflictResolution(\n resourceType: string,\n existingResourceName: string\n): Promise<ConflictAction> {\n const action = await clack.select({\n message: `Found existing ${resourceType}: ${pc.cyan(existingResourceName)}. How should we handle this?`,\n options: [\n {\n value: \"deploy-alongside\",\n label: \"Deploy alongside (no changes)\",\n hint: \"Create our resources without modifying yours\",\n },\n {\n value: \"replace\",\n label: \"Replace with Wraps version\",\n hint: \"Save original for restore, use ours\",\n },\n {\n value: \"skip\",\n label: \"Skip this feature\",\n hint: \"Keep your setup, skip Wraps deployment\",\n },\n ],\n });\n\n if (clack.isCancel(action)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return action as ConflictAction;\n}\n\n/**\n * Prompt to select identities to track\n */\nexport async function promptSelectIdentities(\n identities: Array<{ name: string; verified: boolean }>\n): Promise<string[]> {\n const selected = await clack.multiselect({\n message: \"Select identities to connect with Wraps:\",\n options: identities.map((id) => ({\n value: id.name,\n label: id.name,\n hint: id.verified ? \"Verified\" : \"Pending verification\",\n })),\n required: false,\n });\n\n if (clack.isCancel(selected)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return selected as string[];\n}\n\n/**\n * Confirm connection deployment\n */\nexport async function confirmConnect(): Promise<boolean> {\n const confirmed = await clack.confirm({\n message: \"Connect to existing AWS infrastructure?\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirmed)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return confirmed;\n}\n\n/**\n * Prompt for configuration preset\n */\nexport async function promptConfigPreset(): Promise<\n \"starter\" | \"production\" | \"enterprise\" | \"custom\"\n> {\n const { getAllPresetInfo } = await import(\"../email/presets.js\");\n const presets = getAllPresetInfo();\n\n const preset = await clack.select({\n message: \"Choose a configuration preset:\",\n options: presets.map((p: any) => ({\n value: p.name.toLowerCase() as\n | \"starter\"\n | \"production\"\n | \"enterprise\"\n | \"custom\",\n label: `${p.name} - ${p.description}`,\n hint: `${p.volume} | Est. ${p.estimatedCost}/mo`,\n })),\n });\n\n if (clack.isCancel(preset)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return preset as \"starter\" | \"production\" | \"enterprise\" | \"custom\";\n}\n\n/**\n * Prompt for estimated monthly email volume\n */\nexport async function promptEstimatedVolume(): Promise<number> {\n const volume = await clack.select({\n message: \"Estimated monthly email volume:\",\n options: [\n { value: 1000, label: \"< 1k emails/month\", hint: \"Hobby/Development\" },\n { value: 10_000, label: \"1k-10k emails/month\", hint: \"Side Project\" },\n {\n value: 50_000,\n label: \"10k-100k emails/month\",\n hint: \"Growing Startup\",\n },\n {\n value: 250_000,\n label: \"100k-500k emails/month\",\n hint: \"Production SaaS\",\n },\n { value: 1_000_000, label: \"500k+ emails/month\", hint: \"High Volume\" },\n ],\n });\n\n if (clack.isCancel(volume)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return volume as number;\n}\n\n/**\n * Prompt for custom configuration\n */\n/**\n * Prompt for email archiving configuration (for presets)\n */\nexport async function promptEmailArchiving(): Promise<{\n enabled: boolean;\n retention: ArchiveRetention;\n}> {\n const enabled = await clack.confirm({\n message:\n \"Enable email archiving? (Store full email content with HTML for viewing in dashboard)\",\n initialValue: false,\n });\n\n if (clack.isCancel(enabled)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n if (!enabled) {\n return { enabled: false, retention: \"90days\" };\n }\n\n const retention = await clack.select({\n message: \"Email archive retention period:\",\n options: [\n { value: \"7days\", label: \"7 days\", hint: \"~$1-2/mo for 10k emails\" },\n { value: \"30days\", label: \"30 days\", hint: \"~$2-4/mo for 10k emails\" },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"~$5-10/mo for 10k emails\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"~$15-25/mo for 10k emails\",\n },\n { value: \"1year\", label: \"1 year\", hint: \"~$25-40/mo for 10k emails\" },\n {\n value: \"18months\",\n label: \"18 months\",\n hint: \"~$35-60/mo for 10k emails\",\n },\n ],\n initialValue: \"90days\",\n });\n\n if (clack.isCancel(retention)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n clack.log.info(\n pc.dim(\n \"Archiving stores full RFC 822 emails with HTML, attachments, and headers\"\n )\n );\n clack.log.info(\n pc.dim(\"Cost: $2/GB ingestion + $0.19/GB/month storage (~50KB per email)\")\n );\n\n return {\n enabled: true,\n retention: retention as ArchiveRetention,\n };\n}\n\nexport async function promptCustomConfig(existingConfig?: any): Promise<any> {\n clack.log.info(\"Custom configuration builder\");\n clack.log.info(\"Configure each feature individually\");\n\n // Reputation tracking (first, as it's recommended)\n const reputationMetrics = await clack.confirm({\n message: \"Enable reputation tracking (recommended)?\",\n initialValue: existingConfig?.reputationMetrics ?? true,\n });\n\n if (clack.isCancel(reputationMetrics)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n // Tracking\n const trackingEnabled = await clack.confirm({\n message: \"Enable open & click tracking?\",\n initialValue: existingConfig?.tracking?.enabled ?? true,\n });\n\n if (clack.isCancel(trackingEnabled)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n // Event tracking (combined - EventBridge + DynamoDB)\n const eventTrackingEnabled = await clack.confirm({\n message: \"Store email events in DynamoDB?\",\n initialValue: existingConfig?.eventTracking?.enabled ?? true,\n });\n\n if (clack.isCancel(eventTrackingEnabled)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n let archiveRetention: string | symbol = \"90days\";\n\n if (eventTrackingEnabled) {\n archiveRetention = await clack.select({\n message: \"Event history retention period:\",\n options: [\n { value: \"7days\", label: \"7 days\", hint: \"Minimal storage cost\" },\n { value: \"30days\", label: \"30 days\", hint: \"Development/testing\" },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"Standard retention\",\n },\n { value: \"1year\", label: \"1 year\", hint: \"Compliance requirements\" },\n {\n value: \"indefinite\",\n label: \"Indefinite\",\n hint: \"Higher storage cost\",\n },\n ],\n initialValue:\n existingConfig?.eventTracking?.archiveRetention || \"90days\",\n });\n\n if (clack.isCancel(archiveRetention)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n }\n\n // Security\n const tlsRequired = await clack.confirm({\n message: \"Require TLS encryption for all emails?\",\n initialValue: existingConfig?.tlsRequired ?? true,\n });\n\n if (clack.isCancel(tlsRequired)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n // Custom MAIL FROM domain (for DMARC alignment)\n const customMailFrom = await clack.confirm({\n message: \"Configure custom MAIL FROM domain? (improves DMARC alignment)\",\n initialValue: existingConfig?.mailFromDomain !== undefined,\n });\n\n if (clack.isCancel(customMailFrom)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n let mailFromSubdomain: string | symbol = \"mail\";\n\n if (customMailFrom) {\n mailFromSubdomain = await clack.text({\n message: \"MAIL FROM subdomain:\",\n placeholder: \"mail\",\n initialValue:\n existingConfig?.mailFromDomain?.split(\".\")[0] || \"mail\",\n validate: (value) => {\n if (!value || value.trim() === \"\") {\n return \"Subdomain is required\";\n }\n if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/i.test(value)) {\n return \"Invalid subdomain format\";\n }\n return undefined;\n },\n });\n\n if (clack.isCancel(mailFromSubdomain)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n clack.log.info(\n pc.dim(\n `MAIL FROM will be set to ${mailFromSubdomain}.yourdomain.com`\n )\n );\n }\n\n // Dedicated IP\n const dedicatedIp = await clack.confirm({\n message: \"Request dedicated IP address? (requires 100k+ emails/day)\",\n initialValue: existingConfig?.dedicatedIp ?? false,\n });\n\n if (clack.isCancel(dedicatedIp)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n // Email Archiving\n const emailArchivingEnabled = await clack.confirm({\n message:\n \"Enable email archiving? (Store full email content with HTML for viewing)\",\n initialValue: existingConfig?.emailArchiving?.enabled ?? false,\n });\n\n if (clack.isCancel(emailArchivingEnabled)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n let emailArchiveRetention: string | symbol = \"90days\";\n\n if (emailArchivingEnabled) {\n emailArchiveRetention = await clack.select({\n message: \"Email archive retention period:\",\n options: [\n { value: \"7days\", label: \"7 days\", hint: \"~$1-2/mo for 10k emails\" },\n { value: \"30days\", label: \"30 days\", hint: \"~$2-4/mo for 10k emails\" },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"~$5-10/mo for 10k emails\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"~$15-25/mo for 10k emails\",\n },\n { value: \"1year\", label: \"1 year\", hint: \"~$25-40/mo for 10k emails\" },\n {\n value: \"18months\",\n label: \"18 months\",\n hint: \"~$35-60/mo for 10k emails\",\n },\n ],\n initialValue: existingConfig?.emailArchiving?.retention || \"90days\",\n });\n\n if (clack.isCancel(emailArchiveRetention)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n clack.log.info(\n pc.dim(\n \"Note: Archiving stores full RFC 822 emails with HTML, attachments, and headers\"\n )\n );\n clack.log.info(\n pc.dim(\"Cost: $2/GB ingestion + $0.19/GB/month storage (~50KB per email)\")\n );\n }\n\n return {\n tracking: trackingEnabled\n ? {\n enabled: true,\n opens: true,\n clicks: true,\n }\n : { enabled: false },\n tlsRequired,\n reputationMetrics,\n mailFromSubdomain: customMailFrom\n ? typeof mailFromSubdomain === \"string\"\n ? mailFromSubdomain\n : \"mail\"\n : undefined,\n suppressionList: {\n enabled: true,\n reasons: [\"BOUNCE\", \"COMPLAINT\"],\n },\n eventTracking: eventTrackingEnabled\n ? {\n enabled: true,\n eventBridge: true,\n events: [\n \"SEND\",\n \"DELIVERY\",\n \"OPEN\",\n \"CLICK\",\n \"BOUNCE\",\n \"COMPLAINT\",\n \"REJECT\",\n \"RENDERING_FAILURE\",\n ],\n dynamoDBHistory: true,\n archiveRetention:\n typeof archiveRetention === \"string\" ? archiveRetention : \"90days\",\n }\n : { enabled: false },\n emailArchiving: emailArchivingEnabled\n ? {\n enabled: true,\n retention:\n typeof emailArchiveRetention === \"string\"\n ? emailArchiveRetention\n : \"90days\",\n }\n : { enabled: false, retention: \"90days\" },\n dedicatedIp,\n sendingEnabled: true,\n };\n}\n","import { AssumeRoleCommand, STSClient } from \"@aws-sdk/client-sts\";\n\n/**\n * AWS credential identity type\n */\nexport type AwsCredentialIdentity = {\n accessKeyId: string;\n secretAccessKey: string;\n sessionToken?: string;\n expiration?: Date;\n};\n\n/**\n * Assume IAM role and return temporary credentials\n */\nexport async function assumeRole(\n roleArn: string,\n region: string,\n sessionName = \"wraps-console\"\n): Promise<AwsCredentialIdentity> {\n const sts = new STSClient({ region });\n\n const response = await sts.send(\n new AssumeRoleCommand({\n RoleArn: roleArn,\n RoleSessionName: sessionName,\n DurationSeconds: 3600, // 1 hour\n })\n );\n\n if (!response.Credentials) {\n throw new Error(\"Failed to assume role: No credentials returned\");\n }\n\n return {\n accessKeyId: response.Credentials.AccessKeyId!,\n secretAccessKey: response.Credentials.SecretAccessKey!,\n sessionToken: response.Credentials.SessionToken!,\n expiration: response.Credentials.Expiration,\n };\n}\n","import {\n GetArchiveMessageCommand,\n type GetArchiveMessageCommandOutput,\n GetArchiveSearchResultsCommand,\n MailManagerClient,\n StartArchiveSearchCommand,\n} from \"@aws-sdk/client-mailmanager\";\nimport DOMPurify from \"isomorphic-dompurify\";\nimport { type ParsedMail, simpleParser } from \"mailparser\";\n\n/**\n * Parsed email from archive\n */\nexport type ParsedEmail = {\n messageId: string;\n from: string;\n to: string;\n subject: string;\n html?: string;\n text?: string;\n attachments: Array<{\n filename?: string;\n contentType: string;\n size: number;\n }>;\n headers: Record<string, string | string[] | undefined>;\n timestamp: Date;\n metadata?: {\n senderIp?: string;\n tlsProtocol?: string;\n tlsCipherSuite?: string;\n senderHostname?: string;\n };\n};\n\n/**\n * Extract archive ID from ARN\n * ARN format: arn:aws:ses:region:account-id:mailmanager-archive/archive-id\n * Returns just the archive-id part\n */\nfunction extractArchiveId(archiveArnOrId: string): string {\n if (archiveArnOrId.startsWith(\"arn:\")) {\n // Extract ID from ARN\n const parts = archiveArnOrId.split(\"/\");\n return parts.at(-1) as string;\n }\n // Already just an ID\n return archiveArnOrId;\n}\n\n/**\n * Search criteria for finding archived email\n */\nexport type ArchiveSearchCriteria = {\n from?: string;\n to?: string;\n subject?: string;\n timestamp?: Date;\n};\n\n/**\n * Get an archived email using search criteria\n *\n * This function performs a two-step process:\n * 1. Search the archive using FROM/TO/SUBJECT to find the ArchivedMessageId\n * 2. Retrieve the actual email content using the ArchivedMessageId\n *\n * Note: MailManager Archive doesn't support searching by SES Message-ID directly.\n * We search using FROM, TO, and SUBJECT which we get from DynamoDB events.\n *\n * @param archiveArnOrId Archive ARN or ID (will extract ID if ARN provided)\n * @param searchCriteria Email search criteria (from, to, subject, timestamp)\n * @param region AWS region\n * @returns Parsed email with full content\n */\nexport async function getArchivedEmail(\n archiveArnOrId: string,\n searchCriteria: ArchiveSearchCriteria,\n region: string\n): Promise<ParsedEmail> {\n const client = new MailManagerClient({ region });\n\n // Extract archive ID from ARN if needed\n const archiveId = extractArchiveId(archiveArnOrId);\n\n // Step 1: Search for the message to get the ArchivedMessageId\n // MailManager doesn't support MESSAGE_ID search, so we use FROM/TO/SUBJECT\n // Use timestamp to narrow the search window (±1 day)\n const searchTime = searchCriteria.timestamp || new Date();\n const dayBefore = new Date(searchTime.getTime() - 24 * 60 * 60 * 1000);\n const dayAfter = new Date(searchTime.getTime() + 24 * 60 * 60 * 1000);\n\n // Build search filters\n const filters: any[] = [];\n\n if (searchCriteria.from) {\n filters.push({\n StringExpression: {\n Evaluate: {\n Attribute: \"FROM\",\n },\n Operator: \"CONTAINS\",\n Values: [searchCriteria.from],\n },\n });\n }\n\n if (searchCriteria.to) {\n filters.push({\n StringExpression: {\n Evaluate: {\n Attribute: \"TO\",\n },\n Operator: \"CONTAINS\",\n Values: [searchCriteria.to],\n },\n });\n }\n\n if (searchCriteria.subject) {\n filters.push({\n StringExpression: {\n Evaluate: {\n Attribute: \"SUBJECT\",\n },\n Operator: \"CONTAINS\",\n Values: [searchCriteria.subject],\n },\n });\n }\n\n // If no filters provided, throw error\n if (filters.length === 0) {\n throw new Error(\n \"At least one search criterion (from, to, or subject) is required\"\n );\n }\n\n const searchCommand = new StartArchiveSearchCommand({\n ArchiveId: archiveId,\n FromTimestamp: dayBefore,\n ToTimestamp: dayAfter,\n Filters: {\n Include: filters,\n },\n MaxResults: 10, // Get a few results in case there are multiple matches\n });\n\n const searchResponse = await client.send(searchCommand);\n const searchId = searchResponse.SearchId;\n\n if (!searchId) {\n throw new Error(\"Failed to start archive search\");\n }\n\n // Step 2: Poll for search results (searches are async)\n let archivedMessageId: string | undefined;\n let attempts = 0;\n const maxAttempts = 20; // Increased max attempts\n const pollInterval = 1000; // 1 second between polls\n\n // Wait a bit before first poll to let search start\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n while (attempts < maxAttempts) {\n try {\n const resultsCommand = new GetArchiveSearchResultsCommand({\n SearchId: searchId,\n });\n\n const resultsResponse = await client.send(resultsCommand);\n\n if (resultsResponse.Rows && resultsResponse.Rows.length > 0) {\n // Found the message!\n archivedMessageId = resultsResponse.Rows[0].ArchivedMessageId;\n break;\n }\n\n // No results yet, but search completed - email not found\n if (resultsResponse.Rows && resultsResponse.Rows.length === 0) {\n // Search completed but no results\n break;\n }\n } catch (error: unknown) {\n // If search is still in progress, continue polling\n if (\n error instanceof Error &&\n error.name === \"ConflictException\" &&\n error.message.includes(\"still in progress\")\n ) {\n console.log(`Search still in progress, attempt ${attempts + 1}...`);\n } else {\n // Other errors should be thrown\n throw error;\n }\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n attempts++;\n }\n\n if (!archivedMessageId) {\n throw new Error(\n \"Email not found in archive with the provided search criteria. It may have been sent before archiving was enabled.\"\n );\n }\n\n // Step 3: Get the actual archived message using the ArchivedMessageId\n const command = new GetArchiveMessageCommand({\n ArchivedMessageId: archivedMessageId,\n });\n\n const response: GetArchiveMessageCommandOutput = await client.send(command);\n\n if (!response.MessageDownloadLink) {\n throw new Error(\"No download link available for archived message\");\n }\n\n // Download raw email from presigned S3 URL\n const emailResponse = await fetch(response.MessageDownloadLink);\n if (!emailResponse.ok) {\n throw new Error(`Failed to download email: ${emailResponse.statusText}`);\n }\n\n const emailRaw = await emailResponse.text();\n\n // Parse RFC 822/MIME message\n const parsed: ParsedMail = await simpleParser(emailRaw);\n\n // Extract attachment metadata (don't include full content to save memory)\n const attachments =\n parsed.attachments?.map((att) => ({\n filename: att.filename,\n contentType: att.contentType,\n size: att.size,\n })) || [];\n\n // Convert headers Map to plain object\n const headers: Record<string, string | string[] | undefined> = {};\n if (parsed.headers) {\n for (const [key, value] of parsed.headers) {\n // Convert header values to string/string[]\n if (value instanceof Date) {\n headers[key] = value.toISOString();\n } else if (typeof value === \"string\") {\n headers[key] = value;\n } else if (\n Array.isArray(value) &&\n value.every((v) => typeof v === \"string\")\n ) {\n headers[key] = value as string[];\n } else {\n // Convert complex header types (AddressObject, StructuredHeader, etc.) to string\n headers[key] = JSON.stringify(value);\n }\n }\n }\n\n // Extract from/to as text\n const getAddressText = (\n addr: ParsedMail[\"from\"] | ParsedMail[\"to\"]\n ): string => {\n if (!addr) {\n return \"\";\n }\n if (Array.isArray(addr)) {\n return addr.map((a) => a.text).join(\", \");\n }\n return addr.text || \"\";\n };\n\n return {\n messageId: parsed.messageId || headers[\"message-id\"]?.toString() || \"\",\n from: getAddressText(parsed.from),\n to: getAddressText(parsed.to),\n subject: parsed.subject || \"\",\n html: parsed.html || undefined,\n text: parsed.text || undefined,\n attachments,\n headers,\n timestamp: parsed.date || new Date(),\n // Note: MessageMetadata is not available in GetArchiveMessageCommandOutput\n // These fields would need to be retrieved separately if needed\n metadata: {},\n };\n}\n\n/**\n * Search archived emails\n *\n * TODO: Update this to use the correct Mail Manager Archive Search API:\n * - StartArchiveSearchCommand to initiate search\n * - GetArchiveSearchResultsCommand to retrieve results\n * - Implement polling logic for async search completion\n *\n * @param archiveId Archive ARN or ID\n * @param params Search parameters\n * @param region AWS region\n * @returns Search results\n */\nexport async function searchArchivedEmails(\n archiveId: string,\n params: {\n from?: string;\n to?: string;\n subject?: string;\n startDate?: Date;\n endDate?: Date;\n maxResults?: number;\n },\n region: string\n): Promise<never> {\n // TODO: Implement proper search using StartArchiveSearchCommand\n // and GetArchiveSearchResultsCommand\n // Suppress unused variable warnings\n void archiveId;\n void params;\n void region;\n\n throw new Error(\n \"Archive search is not yet implemented. This requires:\\n\" +\n \"1. Start search with StartArchiveSearchCommand\\n\" +\n \"2. Poll for completion\\n\" +\n \"3. Get results with GetArchiveSearchResultsCommand\"\n );\n}\n\n/**\n * Sanitize HTML for safe rendering using DOMPurify\n * Removes potentially dangerous elements and attributes\n *\n * Uses isomorphic-dompurify which provides secure HTML sanitization\n * that works in both Node.js and browser environments.\n *\n * @param html HTML content to sanitize\n * @returns Sanitized HTML safe for rendering\n */\nexport function sanitizeEmailHtml(html: string): string {\n // DOMPurify provides comprehensive XSS protection including:\n // - Script tag removal (including nested bypass attacks like <scr<script>ipt>)\n // - Event handler removal (onclick, onload, etc.)\n // - Protocol sanitization (javascript:, data:text/html, etc.)\n // - Object/embed/iframe removal\n // - Style-based XSS protection\n return DOMPurify.sanitize(html, {\n // Allow common safe HTML elements for email rendering\n ALLOWED_TAGS: [\n \"p\",\n \"div\",\n \"span\",\n \"a\",\n \"img\",\n \"br\",\n \"strong\",\n \"em\",\n \"b\",\n \"i\",\n \"u\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"ul\",\n \"ol\",\n \"li\",\n \"table\",\n \"thead\",\n \"tbody\",\n \"tr\",\n \"td\",\n \"th\",\n \"blockquote\",\n \"pre\",\n \"code\",\n ],\n ALLOWED_ATTR: [\"href\", \"src\", \"alt\", \"title\", \"class\", \"style\", \"target\"],\n // Keep safe URIs only (removes javascript:, data:text/html, etc.)\n ALLOW_DATA_ATTR: false,\n });\n}\n","import {\n type ArchiveSearchCriteria,\n getArchivedEmail,\n} from \"../../utils/archive.js\";\n\n/**\n * Archived email with full content\n */\nexport type ArchivedEmail = {\n messageId: string;\n from: string;\n to: string;\n subject: string;\n html?: string;\n text?: string;\n attachments: Array<{\n filename?: string;\n contentType: string;\n size: number;\n }>;\n headers: Record<string, string | string[] | undefined>;\n timestamp: Date;\n metadata?: {\n senderIp?: string;\n tlsProtocol?: string;\n tlsCipherSuite?: string;\n senderHostname?: string;\n };\n};\n\ntype FetchArchivedEmailOptions = {\n region: string;\n archiveArn: string;\n from?: string;\n to?: string;\n subject?: string;\n timestamp?: Date;\n};\n\n/**\n * Fetch archived email by message ID from AWS SES Mail Manager\n *\n * This function searches the archive using email metadata (from, to, subject)\n * to find the archived message, since MailManager doesn't support direct\n * search by SES Message-ID.\n *\n * @param messageId Email message ID (for logging/correlation only)\n * @param options Configuration options including search criteria\n * @returns Archived email with full content, or null if not found\n */\nexport async function fetchArchivedEmail(\n messageId: string,\n options: FetchArchivedEmailOptions\n): Promise<ArchivedEmail | null> {\n const { region, archiveArn, from, to, subject, timestamp } = options;\n\n try {\n console.log(\"Fetching archived email:\", {\n messageId,\n archiveArn,\n region,\n });\n\n // Build search criteria from email metadata\n const searchCriteria: ArchiveSearchCriteria = {\n from,\n to,\n subject,\n timestamp,\n };\n\n // Call the archive utility to get the email\n const email = await getArchivedEmail(archiveArn, searchCriteria, region);\n\n console.log(\"Archived email fetched successfully:\", {\n messageId: email.messageId,\n hasHtml: !!email.html,\n hasText: !!email.text,\n attachmentCount: email.attachments.length,\n });\n\n // Return the email data\n return email;\n } catch (error: unknown) {\n // If the email is not found, return null instead of throwing\n if (\n error instanceof Error &&\n (error.message.includes(\"not found\") ||\n error.message.includes(\"ResourceNotFoundException\"))\n ) {\n console.log(\"Archived email not found:\", messageId);\n return null;\n }\n\n // For other errors, log and rethrow\n console.error(\"Error fetching archived email:\", error);\n throw error;\n }\n}\n","import { DynamoDBClient, ScanCommand } from \"@aws-sdk/client-dynamodb\";\nimport { unmarshall } from \"@aws-sdk/util-dynamodb\";\n\nexport type DynamoDBMetrics = {\n opens: Array<{ timestamp: number; value: number }>;\n clicks: Array<{ timestamp: number; value: number }>;\n};\n\n/**\n * Fetch Open and Click metrics from DynamoDB\n */\nexport async function fetchDynamoDBMetrics(\n region: string,\n tableName: string,\n timeRange: { start: Date; end: Date }\n): Promise<DynamoDBMetrics> {\n const dynamodb = new DynamoDBClient({ region });\n\n try {\n const startTime = timeRange.start.getTime();\n const endTime = timeRange.end.getTime();\n\n // Scan the table for events in the time range\n // Note: In production, consider using accountId GSI for better performance\n const response = await dynamodb.send(\n new ScanCommand({\n TableName: tableName,\n FilterExpression:\n \"sentAt BETWEEN :startTime AND :endTime AND (eventType = :open OR eventType = :click)\",\n ExpressionAttributeValues: {\n \":startTime\": { N: startTime.toString() },\n \":endTime\": { N: endTime.toString() },\n \":open\": { S: \"Open\" },\n \":click\": { S: \"Click\" },\n },\n })\n );\n\n const items = (response.Items || []).map((item) => unmarshall(item));\n\n // Group events by 5-minute buckets (to match CloudWatch period)\n const period = 5 * 60 * 1000; // 5 minutes in milliseconds\n const openBuckets = new Map<number, number>();\n const clickBuckets = new Map<number, number>();\n\n for (const item of items) {\n const timestamp = Number(item.sentAt);\n const bucket = Math.floor(timestamp / period) * period;\n const eventType = item.eventType;\n\n if (eventType === \"Open\") {\n openBuckets.set(bucket, (openBuckets.get(bucket) || 0) + 1);\n } else if (eventType === \"Click\") {\n clickBuckets.set(bucket, (clickBuckets.get(bucket) || 0) + 1);\n }\n }\n\n // Convert to array format\n const opens = Array.from(openBuckets.entries()).map(\n ([timestamp, value]) => ({\n timestamp,\n value,\n })\n );\n\n const clicks = Array.from(clickBuckets.entries()).map(\n ([timestamp, value]) => ({\n timestamp,\n value,\n })\n );\n\n return {\n opens: opens.sort((a, b) => a.timestamp - b.timestamp),\n clicks: clicks.sort((a, b) => a.timestamp - b.timestamp),\n };\n } catch (error) {\n console.error(\"Error fetching DynamoDB metrics:\", error);\n // Return empty arrays on error instead of throwing\n return {\n opens: [],\n clicks: [],\n };\n }\n}\n","#!/usr/bin/env node\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as clack from \"@clack/prompts\";\nimport args from \"args\";\nimport pc from \"picocolors\";\n// Dashboard commands\nimport { updateRole } from \"./commands/dashboard/update-role.js\";\nimport { config } from \"./commands/email/config.js\";\n// Email commands\nimport { connect } from \"./commands/email/connect.js\";\nimport { emailDestroy } from \"./commands/email/destroy.js\";\nimport {\n addDomain,\n getDkim,\n listDomains,\n removeDomain,\n verifyDomain,\n} from \"./commands/email/domains.js\";\nimport { init } from \"./commands/email/init.js\";\nimport { restore } from \"./commands/email/restore.js\";\nimport { emailStatus } from \"./commands/email/status.js\";\nimport { upgrade } from \"./commands/email/upgrade.js\";\n// Shared commands\nimport { dashboard } from \"./commands/shared/dashboard.js\";\nimport { destroy } from \"./commands/shared/destroy.js\";\nimport { status } from \"./commands/shared/status.js\";\n// Telemetry commands\nimport {\n telemetryDisable,\n telemetryEnable,\n telemetryStatus,\n} from \"./commands/telemetry.js\";\nimport { getTelemetryClient } from \"./telemetry/client.js\";\nimport { trackCommand } from \"./telemetry/events.js\";\nimport {\n printCompletionScript,\n setupTabCompletion,\n} from \"./utils/shared/completion.js\";\nimport { handleCLIError } from \"./utils/shared/errors.js\";\n\n// Get package version\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst packageJson = JSON.parse(\n readFileSync(join(__dirname, \"../package.json\"), \"utf-8\")\n);\nconst VERSION = packageJson.version;\n\n// Setup tab completion\nsetupTabCompletion();\n\n// Function to show version\nfunction showVersion() {\n console.log(`wraps v${VERSION}`);\n process.exit(0);\n}\n\n// Function to show help\nfunction showHelp() {\n clack.intro(pc.bold(`WRAPS CLI v${VERSION}`));\n console.log(\"Deploy AWS infrastructure to your account\\n\");\n console.log(\"Usage: wraps [service] <command> [options]\\n\");\n console.log(\"Services:\");\n console.log(` ${pc.cyan(\"email\")} Email infrastructure (AWS SES)\\n`);\n console.log(\"Email Commands:\");\n console.log(\n ` ${pc.cyan(\"email init\")} Deploy new email infrastructure`\n );\n console.log(\n ` ${pc.cyan(\"email connect\")} Connect to existing AWS SES`\n );\n console.log(` ${pc.cyan(\"email status\")} Show email infrastructure details`);\n console.log(` ${pc.cyan(\"email verify\")} Verify domain DNS records`);\n console.log(\n ` ${pc.cyan(\"email sync\")} Apply CLI updates to infrastructure`\n );\n console.log(` ${pc.cyan(\"email upgrade\")} Add features`);\n console.log(\n ` ${pc.cyan(\"email restore\")} Restore original configuration`\n );\n console.log(\n ` ${pc.cyan(\"email destroy\")} Remove email infrastructure`\n );\n console.log(` ${pc.cyan(\"email domains add\")} Add a domain to SES`);\n console.log(` ${pc.cyan(\"email domains list\")} List all domains`);\n console.log(` ${pc.cyan(\"email domains remove\")} Remove a domain\\n`);\n console.log(\"Console & Dashboard:\");\n console.log(` ${pc.cyan(\"console\")} Start local web console`);\n console.log(\n ` ${pc.cyan(\"dashboard update-role\")} Update hosted dashboard IAM permissions\\n`\n );\n console.log(\"Global Commands:\");\n console.log(` ${pc.cyan(\"status\")} Show overview of all services`);\n console.log(` ${pc.cyan(\"destroy\")} Remove deployed infrastructure`);\n console.log(` ${pc.cyan(\"completion\")} Generate shell completion script`);\n console.log(\n ` ${pc.cyan(\"telemetry\")} Manage anonymous telemetry settings\\n`\n );\n console.log(\"Options:\");\n console.log(\n ` ${pc.dim(\"-p, --provider\")} Hosting provider (vercel, aws, railway, other)`\n );\n console.log(` ${pc.dim(\"-r, --region\")} AWS region`);\n console.log(` ${pc.dim(\"-d, --domain\")} Domain name`);\n console.log(` ${pc.dim(\"--account\")} AWS account ID or alias`);\n console.log(` ${pc.dim(\"--preset\")} Configuration preset`);\n console.log(` ${pc.dim(\"-y, --yes\")} Skip confirmation prompts`);\n console.log(` ${pc.dim(\"-f, --force\")} Force destructive operations`);\n console.log(\n ` ${pc.dim(\"--preview\")} Preview changes without deploying`\n );\n console.log(` ${pc.dim(\"-v, --version\")} Show version number\\n`);\n console.log(\n `Run ${pc.cyan(\"wraps <service> <command> --help\")} for more information.\\n`\n );\n process.exit(0);\n}\n\n// Check for version before args parses\nif (process.argv.includes(\"--version\") || process.argv.includes(\"-v\")) {\n showVersion();\n}\n\n// Check for help before args parses (to override args' built-in help)\nif (process.argv.includes(\"--help\") || process.argv.includes(\"-h\")) {\n showHelp();\n}\n\n// Configure args\nargs.options([\n {\n name: [\"p\", \"provider\"],\n description: \"Hosting provider (vercel, aws, railway, other)\",\n defaultValue: undefined,\n },\n {\n name: [\"r\", \"region\"],\n description: \"AWS region\",\n defaultValue: undefined,\n },\n {\n name: [\"d\", \"domain\"],\n description: \"Domain name\",\n defaultValue: undefined,\n },\n {\n name: \"account\",\n description: \"AWS account ID or alias\",\n defaultValue: undefined,\n },\n {\n name: \"preset\",\n description:\n \"Configuration preset (starter, production, enterprise, custom)\",\n defaultValue: undefined,\n },\n {\n name: [\"y\", \"yes\"],\n description: \"Skip confirmation prompts (non-destructive operations)\",\n defaultValue: false,\n },\n {\n name: [\"f\", \"force\"],\n description:\n \"Force operation without confirmation (destructive operations)\",\n defaultValue: false,\n },\n {\n name: \"port\",\n description: \"Port for dashboard server\",\n defaultValue: undefined,\n },\n {\n name: \"noOpen\",\n description: \"Don't open browser automatically\",\n defaultValue: false,\n },\n {\n name: \"preview\",\n description: \"Preview changes without deploying\",\n defaultValue: false,\n },\n]);\n\n// Get command and flags\nconst flags = args.parse(process.argv);\nconst [primaryCommand, subCommand] = args.sub;\n\n// If no command provided, show interactive service selection\nif (!primaryCommand) {\n async function selectService() {\n clack.intro(pc.bold(`WRAPS CLI v${VERSION}`));\n console.log(\"Welcome! Let's get started deploying your email infrastructure.\\n\");\n\n // Ask what action they want to take\n const action = await clack.select({\n message: \"What would you like to do?\",\n options: [\n {\n value: \"init\",\n label: \"Deploy new infrastructure\",\n hint: \"Create new AWS SES infrastructure\",\n },\n {\n value: \"connect\",\n label: \"Connect existing infrastructure\",\n hint: \"Connect to existing AWS SES setup\",\n },\n ],\n });\n\n if (clack.isCancel(action)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n // Run the appropriate command\n if (action === \"init\") {\n await init({\n provider: flags.provider,\n region: flags.region,\n domain: flags.domain,\n preset: flags.preset,\n yes: flags.yes,\n preview: flags.preview,\n });\n } else {\n await connect({\n provider: flags.provider,\n region: flags.region,\n yes: flags.yes,\n preview: flags.preview,\n });\n }\n }\n\n selectService().catch(handleCLIError);\n // Early exit - don't run the main run() function\n process.exit(0);\n}\n\n// Route to appropriate command\nasync function run() {\n const startTime = Date.now();\n const telemetry = getTelemetryClient();\n\n // Show first-run telemetry notification\n if (telemetry.shouldShowNotification()) {\n console.log();\n clack.log.info(pc.bold(\"Anonymous Telemetry\"));\n console.log(\n ` Wraps collects ${pc.cyan(\"anonymous usage data\")} to improve the CLI.`\n );\n console.log(\n ` We ${pc.bold(\"never\")} collect: domains, AWS credentials, email content, or PII.`\n );\n console.log(\n ` We ${pc.bold(\"only\")} collect: command names, success/failure, CLI version, OS.`\n );\n console.log();\n console.log(` Opt-out anytime: ${pc.cyan(\"wraps telemetry disable\")}`);\n console.log(` Or set: ${pc.cyan(\"WRAPS_TELEMETRY_DISABLED=1\")}`);\n console.log(` Learn more: ${pc.cyan(\"https://wraps.dev/docs/telemetry\")}`);\n console.log();\n\n telemetry.markNotificationShown();\n }\n\n try {\n // Handle service-specific subcommands (e.g., wraps email init)\n if (primaryCommand === \"email\" && subCommand) {\n switch (subCommand) {\n case \"init\":\n await init({\n provider: flags.provider,\n region: flags.region,\n domain: flags.domain,\n preset: flags.preset,\n yes: flags.yes,\n preview: flags.preview,\n });\n break;\n\n case \"connect\":\n await connect({\n provider: flags.provider,\n region: flags.region,\n yes: flags.yes,\n preview: flags.preview,\n });\n break;\n\n case \"config\":\n case \"sync\":\n await config({\n region: flags.region,\n yes: flags.yes,\n preview: flags.preview,\n });\n break;\n\n case \"upgrade\":\n await upgrade({\n region: flags.region,\n yes: flags.yes,\n preview: flags.preview,\n });\n break;\n\n case \"restore\":\n await restore({\n region: flags.region,\n force: flags.force,\n preview: flags.preview,\n });\n break;\n\n case \"status\":\n await emailStatus({\n account: flags.account,\n });\n break;\n\n case \"verify\": {\n if (!flags.domain) {\n clack.log.error(\"--domain flag is required\");\n console.log(\n `\\nUsage: ${pc.cyan(\"wraps email verify --domain yourapp.com\")}\\n`\n );\n process.exit(1);\n }\n await verifyDomain({ domain: flags.domain });\n break;\n }\n\n case \"domains\": {\n // Handle domains subcommands\n const domainsSubCommand = args.sub[2];\n\n switch (domainsSubCommand) {\n case \"add\": {\n if (!flags.domain) {\n clack.log.error(\"--domain flag is required\");\n console.log(\n `\\nUsage: ${pc.cyan(\"wraps email domains add --domain yourapp.com\")}\\n`\n );\n process.exit(1);\n }\n await addDomain({ domain: flags.domain });\n break;\n }\n\n case \"list\":\n await listDomains();\n break;\n\n case \"verify\": {\n if (!flags.domain) {\n clack.log.error(\"--domain flag is required\");\n console.log(\n `\\nUsage: ${pc.cyan(\"wraps email domains verify --domain yourapp.com\")}\\n`\n );\n process.exit(1);\n }\n await verifyDomain({ domain: flags.domain });\n break;\n }\n\n case \"get-dkim\": {\n if (!flags.domain) {\n clack.log.error(\"--domain flag is required\");\n console.log(\n `\\nUsage: ${pc.cyan(\"wraps email domains get-dkim --domain yourapp.com\")}\\n`\n );\n process.exit(1);\n }\n await getDkim({ domain: flags.domain });\n break;\n }\n\n case \"remove\": {\n if (!flags.domain) {\n clack.log.error(\"--domain flag is required\");\n console.log(\n `\\nUsage: ${pc.cyan(\"wraps email domains remove --domain yourapp.com --force\")}\\n`\n );\n process.exit(1);\n }\n await removeDomain({\n domain: flags.domain,\n force: flags.force,\n });\n break;\n }\n\n default:\n clack.log.error(\n `Unknown domains command: ${domainsSubCommand || \"(none)\"}`\n );\n console.log(\n `\\nAvailable commands: ${pc.cyan(\"add\")}, ${pc.cyan(\"list\")}, ${pc.cyan(\"verify\")}, ${pc.cyan(\"get-dkim\")}, ${pc.cyan(\"remove\")}\\n`\n );\n process.exit(1);\n }\n break;\n }\n\n case \"destroy\":\n await emailDestroy({\n force: flags.force,\n preview: flags.preview,\n });\n break;\n\n default:\n clack.log.error(`Unknown email command: ${subCommand}`);\n console.log(\n `\\nRun ${pc.cyan(\"wraps --help\")} for available commands.\\n`\n );\n process.exit(1);\n }\n // Track email commands (they return early, so track here)\n const emailDuration = Date.now() - startTime;\n const emailCommandName = `email:${subCommand}`;\n trackCommand(emailCommandName, {\n success: true,\n duration_ms: emailDuration,\n service: \"email\",\n });\n return;\n }\n\n // Handle Dashboard subcommands\n if (primaryCommand === \"dashboard\" && subCommand) {\n switch (subCommand) {\n case \"update-role\":\n await updateRole({\n region: flags.region,\n force: flags.force,\n });\n break;\n\n default:\n clack.log.error(`Unknown dashboard command: ${subCommand}`);\n console.log(`\\nAvailable commands: ${pc.cyan(\"update-role\")}\\n`);\n console.log(`Run ${pc.cyan(\"wraps --help\")} for more information.\\n`);\n process.exit(1);\n }\n // Track dashboard commands (they return early, so track here)\n const dashboardDuration = Date.now() - startTime;\n const dashboardCommandName = `dashboard:${subCommand}`;\n trackCommand(dashboardCommandName, {\n success: true,\n duration_ms: dashboardDuration,\n });\n return;\n }\n\n // Handle global commands\n switch (primaryCommand) {\n // Global commands (work across all services)\n case \"status\":\n await status({\n account: flags.account,\n });\n break;\n\n case \"console\":\n await dashboard({\n port: flags.port,\n noOpen: flags.noOpen,\n });\n break;\n\n case \"dashboard\":\n // Deprecated: 'wraps dashboard' without subcommand redirects to 'wraps console'\n if (!subCommand) {\n clack.log.warn(\n `'wraps dashboard' is deprecated. Use ${pc.cyan(\"wraps console\")} instead.`\n );\n await dashboard({\n port: flags.port,\n noOpen: flags.noOpen,\n });\n }\n break;\n\n case \"destroy\":\n await destroy({\n force: flags.force,\n preview: flags.preview,\n });\n break;\n\n case \"completion\":\n printCompletionScript();\n break;\n\n case \"telemetry\": {\n // Handle telemetry subcommands\n switch (subCommand) {\n case \"enable\":\n await telemetryEnable();\n break;\n\n case \"disable\":\n await telemetryDisable();\n break;\n\n case \"status\":\n case undefined:\n await telemetryStatus();\n break;\n\n default:\n clack.log.error(`Unknown telemetry command: ${subCommand}`);\n console.log(\n `\\nAvailable commands: ${pc.cyan(\"enable\")}, ${pc.cyan(\"disable\")}, ${pc.cyan(\"status\")}\\n`\n );\n process.exit(1);\n }\n break;\n }\n\n // Show help for service without subcommand\n case \"email\":\n console.log(\n `\\nPlease specify a command for ${primaryCommand} service.\\n`\n );\n showHelp();\n break;\n\n default:\n clack.log.error(`Unknown command: ${primaryCommand}`);\n console.log(\n `\\nRun ${pc.cyan(\"wraps --help\")} for available commands.\\n`\n );\n process.exit(1);\n }\n // Track successful command execution\n const duration = Date.now() - startTime;\n const commandName = subCommand\n ? `${primaryCommand}:${subCommand}`\n : primaryCommand;\n\n trackCommand(commandName, {\n success: true,\n duration_ms: duration,\n });\n } catch (error) {\n // Track failed command execution\n const duration = Date.now() - startTime;\n const commandName = subCommand\n ? `${primaryCommand}:${subCommand}`\n : primaryCommand;\n\n trackCommand(commandName, {\n success: false,\n duration_ms: duration,\n });\n\n handleCLIError(error);\n } finally {\n // Ensure telemetry events are sent before exit\n await telemetry.shutdown();\n }\n}\n\nrun();\n","import { GetRoleCommand, IAMClient } from \"@aws-sdk/client-iam\";\nimport { confirm, intro, isCancel, log, outro } from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport type { UpdateRoleOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { loadConnectionMetadata } from \"../../utils/shared/metadata.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\n\n/**\n * Update hosted dashboard access role command\n *\n * Updates the wraps-console-access-role IAM role with the latest permissions\n * needed for feature detection in the hosted dashboard app (e.g., dynamodb:DescribeTable).\n *\n * This role is created when you connect AWS accounts through the hosted dashboard.\n * This command updates its permissions to match your current infrastructure setup.\n *\n * This command:\n * - Only updates the role if it exists (does not create it)\n * - Updates inline policies to match current feature requirements\n * - Preserves the trust policy (AssumeRole configuration)\n */\nexport async function updateRole(options: UpdateRoleOptions): Promise<void> {\n intro(pc.bold(\"Update Hosted Dashboard Access Role\"));\n\n const progress = new DeploymentProgress();\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region\n const region = options.region || (await getAWSRegion());\n\n // 3. Load metadata to check if deployment exists\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n if (!metadata) {\n progress.stop();\n log.error(\n `No Wraps deployment found for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n console.log(\n `\\nRun ${pc.cyan(\"wraps email init\")} to deploy infrastructure first.\\n`\n );\n process.exit(1);\n }\n\n // 4. Check if wraps-console-access-role exists\n const roleName = \"wraps-console-access-role\";\n const iam = new IAMClient({ region: \"us-east-1\" }); // IAM is global\n\n let roleExists = false;\n try {\n await iam.send(new GetRoleCommand({ RoleName: roleName }));\n roleExists = true;\n } catch (error) {\n if (\n error &&\n typeof error === \"object\" &&\n \"name\" in error &&\n error.name !== \"NoSuchEntity\"\n ) {\n throw error;\n }\n }\n\n if (!roleExists) {\n progress.stop();\n log.warn(`IAM role ${pc.cyan(roleName)} does not exist`);\n console.log(\n \"\\nThis role is created when you connect AWS accounts through the hosted dashboard.\"\n );\n console.log(\n \"If you haven't connected an AWS account to the hosted dashboard yet, there's nothing to update.\\n\"\n );\n process.exit(0);\n }\n\n progress.info(`Found IAM role: ${pc.cyan(roleName)}`);\n\n // 5. Confirm update (unless --force)\n if (!options.force) {\n progress.stop();\n const shouldContinue = await confirm({\n message: `Update IAM role ${pc.cyan(roleName)} with latest permissions?`,\n initialValue: true,\n });\n\n if (isCancel(shouldContinue) || !shouldContinue) {\n outro(\"Update cancelled\");\n process.exit(0);\n }\n }\n\n // 6. Build updated policy\n const emailConfig = metadata.services.email?.config;\n const policy = buildConsolePolicyDocument(emailConfig);\n\n // Extract config values for display\n const sendingEnabled =\n !emailConfig ||\n (emailConfig.sendingEnabled as boolean | undefined) !== false;\n const eventTracking = emailConfig?.eventTracking as\n | Record<string, unknown>\n | undefined;\n const emailArchiving = emailConfig?.emailArchiving as\n | Record<string, unknown>\n | undefined;\n\n // 7. Update role policy\n await progress.execute(\"Updating IAM role permissions\", async () => {\n const { PutRolePolicyCommand } = await import(\"@aws-sdk/client-iam\");\n\n await iam.send(\n new PutRolePolicyCommand({\n RoleName: roleName,\n PolicyName: \"wraps-console-access-policy\",\n PolicyDocument: JSON.stringify(policy, null, 2),\n })\n );\n });\n\n progress.stop();\n\n // Success\n outro(pc.green(\"✓ Hosted dashboard access role updated successfully\"));\n\n console.log(`\\n${pc.bold(\"Updated Permissions:\")}`);\n console.log(\n ` ${pc.green(\"✓\")} SES metrics and identity verification (always enabled)`\n );\n console.log(` ${pc.green(\"✓\")} SES template management (always enabled)`);\n\n if (sendingEnabled) {\n console.log(` ${pc.green(\"✓\")} Email sending via SES`);\n }\n\n if (eventTracking?.dynamoDBHistory) {\n console.log(\n ` ${pc.green(\"✓\")} DynamoDB read access (including DescribeTable)`\n );\n }\n\n if (eventTracking?.enabled) {\n console.log(` ${pc.green(\"✓\")} EventBridge and SQS access`);\n }\n\n if (emailArchiving?.enabled) {\n console.log(` ${pc.green(\"✓\")} Mail Manager Archive access`);\n }\n\n console.log(\n `\\n${pc.dim(\"The hosted dashboard will now have updated permissions for feature detection.\")}\\n`\n );\n}\n\n/**\n * Build IAM policy document for hosted dashboard access role\n *\n * This mirrors the permissions from the main wraps-email-role but is used\n * for the hosted dashboard app (not for SDK sending or local console).\n */\ntype PolicyStatement = {\n Effect: string;\n Action: string[];\n Resource: string | string[];\n};\n\ntype PolicyDocument = {\n Version: string;\n Statement: PolicyStatement[];\n};\n\nfunction buildConsolePolicyDocument(\n emailConfig: Record<string, unknown> | undefined\n): PolicyDocument {\n const statements: PolicyStatement[] = [];\n\n // Always allow reading SES metrics for dashboard\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"ses:GetSendStatistics\",\n \"ses:ListIdentities\",\n \"ses:GetIdentityVerificationAttributes\",\n \"cloudwatch:GetMetricData\",\n \"cloudwatch:GetMetricStatistics\",\n ],\n Resource: \"*\",\n });\n\n // Always allow SES template management (for publishing email templates)\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"ses:GetTemplate\",\n \"ses:ListTemplates\",\n \"ses:CreateTemplate\",\n \"ses:UpdateTemplate\",\n \"ses:DeleteTemplate\",\n \"ses:TestRenderTemplate\",\n ],\n Resource: \"*\",\n });\n\n // Allow sending if enabled\n const sendingEnabled = !emailConfig || emailConfig.sendingEnabled !== false;\n if (sendingEnabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"ses:SendEmail\",\n \"ses:SendRawEmail\",\n \"ses:SendTemplatedEmail\",\n \"ses:SendBulkTemplatedEmail\",\n ],\n Resource: \"*\",\n });\n }\n\n // Allow DynamoDB access if history storage enabled\n const eventTracking = emailConfig?.eventTracking as\n | Record<string, unknown>\n | undefined;\n if (eventTracking?.dynamoDBHistory) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"dynamodb:PutItem\",\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n \"dynamodb:Scan\",\n \"dynamodb:BatchGetItem\",\n \"dynamodb:DescribeTable\",\n ],\n Resource: [\n \"arn:aws:dynamodb:*:*:table/wraps-email-*\",\n \"arn:aws:dynamodb:*:*:table/wraps-email-*/index/*\",\n ],\n });\n }\n\n // Allow EventBridge access if event tracking enabled\n if (eventTracking?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\"events:PutEvents\", \"events:DescribeEventBus\"],\n Resource: \"arn:aws:events:*:*:event-bus/wraps-email-*\",\n });\n }\n\n // Allow SQS access if event tracking enabled\n if (eventTracking?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"sqs:SendMessage\",\n \"sqs:ReceiveMessage\",\n \"sqs:DeleteMessage\",\n \"sqs:GetQueueAttributes\",\n ],\n Resource: \"arn:aws:sqs:*:*:wraps-email-*\",\n });\n }\n\n // Allow Mail Manager Archive access if email archiving enabled\n const emailArchiving = emailConfig?.emailArchiving as\n | Record<string, unknown>\n | undefined;\n if (emailArchiving?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"ses:StartArchiveSearch\",\n \"ses:GetArchiveSearchResults\",\n \"ses:GetArchiveMessage\",\n \"ses:GetArchiveMessageContent\",\n \"ses:GetArchive\",\n \"ses:ListArchives\",\n \"ses:StartArchiveExport\",\n \"ses:GetArchiveExport\",\n ],\n Resource: \"arn:aws:ses:*:*:mailmanager-archive/*\",\n });\n }\n\n return {\n Version: \"2012-10-17\",\n Statement: statements,\n };\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type {\n EmailConfigPreset,\n Provider,\n ServiceType,\n SMSConfigPreset,\n WrapsEmailConfig,\n WrapsSMSConfig,\n} from \"../../types/index.js\";\nimport { ensureWrapsDir, getWrapsDir } from \"./fs.js\";\n\n/**\n * Service-specific configuration with metadata\n */\nexport type ServiceConfig<TConfig, TPreset> = {\n preset?: TPreset;\n config: TConfig;\n pulumiStackName?: string;\n deployedAt: string;\n};\n\n/**\n * Connection metadata - supports multiple services per AWS account/region\n */\nexport type ConnectionMetadata = {\n version: string; // Metadata format version (e.g., \"1.0.0\")\n accountId: string;\n region: string;\n provider: Provider;\n timestamp: string; // Last updated timestamp\n vercel?: {\n teamSlug: string;\n projectName: string;\n };\n\n // Service-specific configurations\n services: {\n email?: ServiceConfig<WrapsEmailConfig, EmailConfigPreset>;\n sms?: ServiceConfig<WrapsSMSConfig, SMSConfigPreset>;\n };\n};\n\n/**\n * Legacy connection metadata (for backwards compatibility)\n * @deprecated Use ConnectionMetadata instead\n */\nexport type LegacyConnectionMetadata = {\n accountId: string;\n region: string;\n provider: Provider;\n timestamp: string;\n preset?: EmailConfigPreset;\n emailConfig: WrapsEmailConfig;\n vercel?: {\n teamSlug: string;\n projectName: string;\n };\n pulumiStackName?: string;\n};\n\n/**\n * Get the connections directory\n */\nfunction getConnectionsDir(): string {\n return join(getWrapsDir(), \"connections\");\n}\n\n/**\n * Get metadata file path for an account and region\n */\nfunction getMetadataPath(accountId: string, region: string): string {\n return join(getConnectionsDir(), `${accountId}-${region}.json`);\n}\n\n/**\n * Ensure the connections directory exists\n */\nasync function ensureConnectionsDir(): Promise<void> {\n await ensureWrapsDir();\n const connectionsDir = getConnectionsDir();\n if (!existsSync(connectionsDir)) {\n const { mkdir } = await import(\"node:fs/promises\");\n await mkdir(connectionsDir, { recursive: true });\n }\n}\n\n/**\n * Migrate legacy metadata to new multi-service format\n */\nfunction migrateLegacyMetadata(\n legacy: LegacyConnectionMetadata\n): ConnectionMetadata {\n return {\n version: \"1.0.0\",\n accountId: legacy.accountId,\n region: legacy.region,\n provider: legacy.provider,\n timestamp: legacy.timestamp,\n vercel: legacy.vercel,\n services: {\n email: {\n preset: legacy.preset,\n config: legacy.emailConfig,\n pulumiStackName: legacy.pulumiStackName,\n deployedAt: legacy.timestamp,\n },\n },\n };\n}\n\n/**\n * Check if metadata is in legacy format\n */\nfunction isLegacyMetadata(data: any): data is LegacyConnectionMetadata {\n return (\n \"emailConfig\" in data &&\n !(\"services\" in data) &&\n typeof data.emailConfig === \"object\"\n );\n}\n\n/**\n * Load connection metadata from disk\n * Automatically migrates legacy format to new multi-service format\n */\nexport async function loadConnectionMetadata(\n accountId: string,\n region: string\n): Promise<ConnectionMetadata | null> {\n const metadataPath = getMetadataPath(accountId, region);\n\n if (!existsSync(metadataPath)) {\n return null;\n }\n\n try {\n const content = await readFile(metadataPath, \"utf-8\");\n const data = JSON.parse(content);\n\n // Migrate legacy format if needed\n if (isLegacyMetadata(data)) {\n const migrated = migrateLegacyMetadata(data);\n // Save migrated version\n await saveConnectionMetadata(migrated);\n return migrated;\n }\n\n // Add version if missing (for backwards compatibility with early multi-service format)\n if (!data.version) {\n data.version = \"1.0.0\";\n await saveConnectionMetadata(data);\n }\n\n return data as ConnectionMetadata;\n } catch (error: any) {\n console.error(\"Error loading connection metadata:\", error.message);\n return null;\n }\n}\n\n/**\n * Save connection metadata to disk\n */\nexport async function saveConnectionMetadata(\n metadata: ConnectionMetadata\n): Promise<void> {\n await ensureConnectionsDir();\n const metadataPath = getMetadataPath(metadata.accountId, metadata.region);\n\n try {\n const content = JSON.stringify(metadata, null, 2);\n await writeFile(metadataPath, content, \"utf-8\");\n } catch (error: any) {\n console.error(\"Error saving connection metadata:\", error.message);\n throw error;\n }\n}\n\n/**\n * Delete connection metadata\n */\nexport async function deleteConnectionMetadata(\n accountId: string,\n region: string\n): Promise<void> {\n const metadataPath = getMetadataPath(accountId, region);\n\n if (existsSync(metadataPath)) {\n const { unlink } = await import(\"node:fs/promises\");\n await unlink(metadataPath);\n }\n}\n\n/**\n * List all connections\n */\nexport async function listConnections(): Promise<ConnectionMetadata[]> {\n const connectionsDir = getConnectionsDir();\n\n if (!existsSync(connectionsDir)) {\n return [];\n }\n\n try {\n const { readdir } = await import(\"node:fs/promises\");\n const files = await readdir(connectionsDir);\n const connections: ConnectionMetadata[] = [];\n\n for (const file of files) {\n if (file.endsWith(\".json\")) {\n const content = await readFile(join(connectionsDir, file), \"utf-8\");\n try {\n const metadata = JSON.parse(content) as ConnectionMetadata;\n connections.push(metadata);\n } catch (error) {\n console.error(`Error parsing ${file}:`, error);\n }\n }\n }\n\n return connections;\n } catch (error: any) {\n console.error(\"Error listing connections:\", error.message);\n return [];\n }\n}\n\n/**\n * Check if a connection exists\n */\nexport async function connectionExists(\n accountId: string,\n region: string\n): Promise<boolean> {\n const metadataPath = getMetadataPath(accountId, region);\n return existsSync(metadataPath);\n}\n\n/**\n * Create initial connection metadata\n * @deprecated Use addServiceToConnection instead\n */\nexport function createConnectionMetadata(\n accountId: string,\n region: string,\n provider: Provider,\n emailConfig: WrapsEmailConfig,\n preset?: EmailConfigPreset\n): ConnectionMetadata {\n return {\n version: \"1.0.0\",\n accountId,\n region,\n provider,\n timestamp: new Date().toISOString(),\n services: {\n email: {\n preset,\n config: emailConfig,\n deployedAt: new Date().toISOString(),\n },\n },\n };\n}\n\n/**\n * Apply config updates to existing config while preserving user-customized fields.\n *\n * This function starts with the existing config and applies updates,\n * while ensuring user-customized fields are never lost:\n * - domain (sending identity)\n * - mailFromDomain (custom MAIL FROM subdomain)\n * - tracking.customRedirectDomain (custom tracking domain)\n * - tracking.httpsEnabled (HTTPS tracking via CloudFront)\n */\nexport function applyConfigUpdates(\n existingConfig: WrapsEmailConfig,\n updates: Partial<WrapsEmailConfig>\n): WrapsEmailConfig {\n // Start with existing config (ensures all required fields are present)\n const result = { ...existingConfig };\n\n // Apply each update, with special handling for nested objects\n for (const [key, value] of Object.entries(updates)) {\n if (value === undefined) {\n continue;\n }\n\n if (key === \"tracking\" && typeof value === \"object\") {\n // Merge tracking updates while preserving user-customized fields\n const trackingUpdate = value as NonNullable<WrapsEmailConfig[\"tracking\"]>;\n result.tracking = {\n ...result.tracking,\n ...trackingUpdate,\n // Always preserve these if they exist in original\n customRedirectDomain:\n result.tracking?.customRedirectDomain ||\n trackingUpdate.customRedirectDomain,\n httpsEnabled:\n result.tracking?.httpsEnabled ?? trackingUpdate.httpsEnabled,\n };\n } else if (key === \"eventTracking\" && typeof value === \"object\") {\n // Deep merge eventTracking\n result.eventTracking = {\n ...result.eventTracking,\n ...(value as NonNullable<WrapsEmailConfig[\"eventTracking\"]>),\n } as NonNullable<WrapsEmailConfig[\"eventTracking\"]>;\n } else if (key === \"suppressionList\" && typeof value === \"object\") {\n // Deep merge suppressionList\n result.suppressionList = {\n ...result.suppressionList,\n ...(value as NonNullable<WrapsEmailConfig[\"suppressionList\"]>),\n } as NonNullable<WrapsEmailConfig[\"suppressionList\"]>;\n } else if (key === \"emailArchiving\" && typeof value === \"object\") {\n // Deep merge emailArchiving\n result.emailArchiving = {\n ...result.emailArchiving,\n ...(value as NonNullable<WrapsEmailConfig[\"emailArchiving\"]>),\n } as NonNullable<WrapsEmailConfig[\"emailArchiving\"]>;\n } else {\n // Direct assignment for primitives and other objects\n result[key as keyof WrapsEmailConfig] = value as any;\n }\n }\n\n return result;\n}\n\n/**\n * Update email configuration in metadata\n * @deprecated Use updateServiceConfig instead\n */\nexport function updateEmailConfig(\n metadata: ConnectionMetadata,\n emailConfig: Partial<WrapsEmailConfig>\n): void {\n if (!metadata.services.email) {\n throw new Error(\"Email service not configured in metadata\");\n }\n\n // Apply updates while preserving user-customized fields\n metadata.services.email.config = applyConfigUpdates(\n metadata.services.email.config,\n emailConfig\n );\n\n metadata.timestamp = new Date().toISOString();\n}\n\n/**\n * Add a service to an existing connection or create new connection metadata\n */\nexport function addServiceToConnection(\n accountId: string,\n region: string,\n provider: Provider,\n service: ServiceType,\n config: WrapsEmailConfig | WrapsSMSConfig,\n preset?: EmailConfigPreset | SMSConfigPreset,\n existingMetadata?: ConnectionMetadata\n): ConnectionMetadata {\n const timestamp = new Date().toISOString();\n\n if (existingMetadata) {\n // Add service to existing connection\n if (service === \"email\") {\n existingMetadata.services.email = {\n preset: preset as EmailConfigPreset,\n config: config as WrapsEmailConfig,\n deployedAt: timestamp,\n };\n } else if (service === \"sms\") {\n existingMetadata.services.sms = {\n preset: preset as SMSConfigPreset,\n config: config as WrapsSMSConfig,\n deployedAt: timestamp,\n };\n }\n existingMetadata.timestamp = timestamp;\n return existingMetadata;\n }\n\n // Create new connection metadata\n const metadata: ConnectionMetadata = {\n version: \"1.0.0\",\n accountId,\n region,\n provider,\n timestamp,\n services: {},\n };\n\n if (service === \"email\") {\n metadata.services.email = {\n preset: preset as EmailConfigPreset,\n config: config as WrapsEmailConfig,\n deployedAt: timestamp,\n };\n } else if (service === \"sms\") {\n metadata.services.sms = {\n preset: preset as SMSConfigPreset,\n config: config as WrapsSMSConfig,\n deployedAt: timestamp,\n };\n }\n\n return metadata;\n}\n\n/**\n * Update service configuration in metadata\n */\nexport function updateServiceConfig<T extends ServiceType>(\n metadata: ConnectionMetadata,\n service: T,\n config: T extends \"email\"\n ? Partial<WrapsEmailConfig>\n : T extends \"sms\"\n ? Partial<WrapsSMSConfig>\n : never\n): void {\n if (service === \"email\" && metadata.services.email) {\n metadata.services.email.config = {\n ...metadata.services.email.config,\n ...(config as Partial<WrapsEmailConfig>),\n };\n } else if (service === \"sms\" && metadata.services.sms) {\n metadata.services.sms.config = {\n ...metadata.services.sms.config,\n ...(config as Partial<WrapsSMSConfig>),\n };\n } else {\n throw new Error(`${service} service not configured in metadata`);\n }\n\n metadata.timestamp = new Date().toISOString();\n}\n\n/**\n * Remove a service from connection metadata\n */\nexport function removeServiceFromConnection(\n metadata: ConnectionMetadata,\n service: ServiceType\n): void {\n if (service === \"email\") {\n const { email, ...rest } = metadata.services;\n metadata.services = rest;\n } else if (service === \"sms\") {\n const { sms, ...rest } = metadata.services;\n metadata.services = rest;\n }\n metadata.timestamp = new Date().toISOString();\n}\n\n/**\n * Check if a service is configured in metadata\n */\nexport function hasService(\n metadata: ConnectionMetadata,\n service: ServiceType\n): boolean {\n if (service === \"email\") {\n return metadata.services.email !== undefined;\n }\n if (service === \"sms\") {\n return metadata.services.sms !== undefined;\n }\n return false;\n}\n\n/**\n * Get list of configured services in metadata\n */\nexport function getConfiguredServices(\n metadata: ConnectionMetadata\n): ServiceType[] {\n const services: ServiceType[] = [];\n if (metadata.services.email) {\n services.push(\"email\");\n }\n if (metadata.services.sms) {\n services.push(\"sms\");\n }\n return services;\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * Get the Wraps configuration directory\n */\nexport function getWrapsDir(): string {\n return join(homedir(), \".wraps\");\n}\n\n/**\n * Get the Pulumi workspace directory\n */\nexport function getPulumiWorkDir(): string {\n return join(getWrapsDir(), \"pulumi\");\n}\n\n/**\n * Ensure the Wraps configuration directory exists\n */\nexport async function ensureWrapsDir(): Promise<void> {\n const wrapsDir = getWrapsDir();\n if (!existsSync(wrapsDir)) {\n await mkdir(wrapsDir, { recursive: true });\n }\n}\n\n/**\n * Ensure the Pulumi workspace directory exists and configure local backend\n */\nexport async function ensurePulumiWorkDir(): Promise<void> {\n await ensureWrapsDir();\n const pulumiDir = getPulumiWorkDir();\n if (!existsSync(pulumiDir)) {\n await mkdir(pulumiDir, { recursive: true });\n }\n\n // Set Pulumi to use local backend (file-based state)\n // This avoids needing to login to Pulumi Cloud\n process.env.PULUMI_BACKEND_URL = `file://${pulumiDir}`;\n process.env.PULUMI_CONFIG_PASSPHRASE = \"\"; // Empty passphrase for simplicity\n}\n","import * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\n\n/**\n * Deployment progress tracker with spinners using clack\n */\nexport class DeploymentProgress {\n private currentSpinner: ReturnType<typeof clack.spinner> | null = null;\n\n /**\n * Start a spinner with a message\n */\n start(message: string) {\n this.currentSpinner = clack.spinner();\n this.currentSpinner.start(message);\n }\n\n /**\n * Mark current step as succeeded\n */\n succeed(message: string) {\n if (this.currentSpinner) {\n this.currentSpinner.stop(message);\n }\n clack.log.success(message);\n }\n\n /**\n * Mark current step as failed\n */\n fail(message: string) {\n if (this.currentSpinner) {\n this.currentSpinner.stop(message);\n }\n clack.log.error(message);\n }\n\n /**\n * Show info message\n */\n info(message: string) {\n clack.log.info(message);\n }\n\n /**\n * Show step message\n */\n step(message: string) {\n clack.log.step(message);\n }\n\n /**\n * Execute a step with automatic spinner handling\n */\n async execute<T>(message: string, fn: () => Promise<T>): Promise<T> {\n this.start(message);\n try {\n const result = await fn();\n this.succeed(message);\n return result;\n } catch (error) {\n this.fail(message);\n throw error;\n }\n }\n\n /**\n * Stop the spinner\n */\n stop(message?: string) {\n if (this.currentSpinner) {\n this.currentSpinner.stop(message || \"\");\n }\n }\n}\n\n/**\n * DNS record type\n */\nexport type DNSRecord = {\n name: string;\n type: string;\n value: string;\n};\n\n/**\n * Success output configuration\n */\nexport type SuccessOutputs = {\n roleArn: string;\n configSetName?: string;\n region: string;\n dnsRecords?: DNSRecord[];\n trackingDomainDnsRecords?: DNSRecord[];\n acmValidationRecords?: DNSRecord[];\n tableName?: string;\n dnsAutoCreated?: boolean;\n domain?: string;\n customTrackingDomain?: string;\n httpsTrackingEnabled?: boolean;\n mailFromDomain?: string;\n};\n\n/**\n * Display success message with infrastructure outputs\n */\nexport function displaySuccess(outputs: SuccessOutputs) {\n const lines = [\n \"\",\n pc.bold(\"Role ARN:\"),\n ` ${pc.cyan(outputs.roleArn)}`,\n \"\",\n `${pc.bold(\"Region:\")} ${pc.cyan(outputs.region)}`,\n ];\n\n if (outputs.configSetName) {\n lines.push(`${pc.bold(\"Config Set:\")} ${pc.cyan(outputs.configSetName)}`);\n }\n\n if (outputs.tableName) {\n lines.push(`${pc.bold(\"DynamoDB Table:\")} ${pc.cyan(outputs.tableName)}`);\n }\n\n lines.push(\n \"\",\n pc.bold(\"Next steps:\"),\n ` 1. Install SDK: ${pc.yellow(\"npm install @wraps/sdk\")}`,\n ` 2. View dashboard: ${pc.blue(\"https://app.wraps.dev\")}`,\n \"\"\n );\n\n clack.outro(pc.green(\"Email infrastructure deployed successfully!\"));\n console.log(lines.join(\"\\n\"));\n\n // Show DNS auto-creation message\n if (outputs.dnsAutoCreated && outputs.domain) {\n clack.note(\n `DNS records (DKIM, SPF, DMARC) were automatically created in Route53 for ${pc.cyan(\n outputs.domain\n )}.\\n\\nVerification should complete within a few minutes.`,\n pc.green(\"✓ DNS Auto-Configured\")\n );\n }\n\n if (outputs.dnsRecords && outputs.dnsRecords.length > 0) {\n // Extract domain from first DKIM record\n const domain = outputs.dnsRecords[0]?.name.split(\"._domainkey.\")[1];\n\n const dnsLines = [\n pc.bold(\"DKIM Records (CNAME):\"),\n ...outputs.dnsRecords.map(\n (record) =>\n ` ${pc.cyan(record.name)} ${pc.dim(record.type)} \"${record.value}\"`\n ),\n ];\n\n if (domain) {\n // Use MAIL FROM domain for DMARC rua if configured, otherwise use main domain\n const dmarcRuaDomain = outputs.mailFromDomain || domain;\n dnsLines.push(\n \"\",\n pc.bold(\"SPF Record (TXT):\"),\n ` ${pc.cyan(domain)} ${pc.dim(\"TXT\")} \"v=spf1 include:amazonses.com ~all\"`,\n pc.dim(\" Note: If you have an existing SPF record, add 'include:amazonses.com' to it\"),\n \"\",\n pc.bold(\"DMARC Record (TXT):\"),\n ` ${pc.cyan(`_dmarc.${domain}`)} ${pc.dim(\"TXT\")} \"v=DMARC1; p=quarantine; rua=mailto:postmaster@${dmarcRuaDomain}\"`\n );\n\n // Add MAIL FROM domain DNS records if configured\n if (outputs.mailFromDomain) {\n dnsLines.push(\n \"\",\n pc.bold(\"MAIL FROM Domain Records (for DMARC alignment):\"),\n ` ${pc.cyan(outputs.mailFromDomain)} ${pc.dim(\"MX\")} \"10 feedback-smtp.${outputs.region}.amazonses.com\"`,\n ` ${pc.cyan(outputs.mailFromDomain)} ${pc.dim(\"TXT\")} \"v=spf1 include:amazonses.com ~all\"`\n );\n }\n }\n\n clack.note(dnsLines.join(\"\\n\"), \"DNS Records to add:\");\n }\n\n // Show ACM certificate validation records if HTTPS tracking is enabled\n if (outputs.acmValidationRecords && outputs.acmValidationRecords.length > 0) {\n const acmDnsLines = [\n pc.bold(\"SSL Certificate Validation (ACM):\"),\n ...outputs.acmValidationRecords.map(\n (record) =>\n ` ${pc.cyan(record.name)} ${pc.dim(record.type)} \"${record.value}\"`\n ),\n \"\",\n pc.dim(\n \"Note: These records are required to validate your SSL certificate.\"\n ),\n pc.dim(\n \"CloudFront will be enabled automatically after certificate validation.\"\n ),\n ];\n\n clack.note(\n acmDnsLines.join(\"\\n\"),\n \"SSL Certificate Validation DNS Records:\"\n );\n }\n\n // Show tracking domain DNS records if custom tracking domain is configured\n if (\n outputs.trackingDomainDnsRecords &&\n outputs.trackingDomainDnsRecords.length > 0\n ) {\n const trackingProtocol = outputs.httpsTrackingEnabled ? \"HTTPS\" : \"HTTP\";\n const trackingDnsLines = [\n pc.bold(`Custom Tracking Domain - ${trackingProtocol} Redirect CNAME:`),\n ...outputs.trackingDomainDnsRecords.map(\n (record) =>\n ` ${pc.cyan(record.name)} ${pc.dim(record.type)} \"${record.value}\"`\n ),\n \"\",\n pc.dim(\n \"Note: This CNAME allows SES to rewrite links in your emails to use\"\n ),\n pc.dim(\"your custom domain for open and click tracking.\"),\n ];\n\n if (outputs.httpsTrackingEnabled) {\n trackingDnsLines.push(\n \"\",\n pc.dim(\"HTTPS tracking is enabled via CloudFront with SSL certificate.\")\n );\n }\n\n clack.note(\n trackingDnsLines.join(\"\\n\"),\n \"Custom Tracking Domain DNS Records:\"\n );\n\n if (outputs.customTrackingDomain) {\n console.log(\n `\\n${pc.dim(\"Run:\")} ${pc.yellow(`wraps email verify --domain ${outputs.customTrackingDomain}`)} ${pc.dim(\n \"(after DNS propagates)\"\n )}\\n`\n );\n }\n }\n\n // Show tracking domain separately if we only have tracking domain (no other DNS records)\n // ONLY for HTTP tracking - HTTPS tracking DNS records are shown after CloudFront is created\n if (\n outputs.customTrackingDomain &&\n !outputs.httpsTrackingEnabled && // Only show for HTTP tracking\n !outputs.dnsAutoCreated &&\n (!outputs.dnsRecords || outputs.dnsRecords.length === 0) &&\n (!outputs.trackingDomainDnsRecords ||\n outputs.trackingDomainDnsRecords.length === 0)\n ) {\n const trackingLines = [\n pc.bold(\"Tracking Domain (CNAME):\"),\n ` ${pc.cyan(outputs.customTrackingDomain)} ${pc.dim(\"CNAME\")} \"r.${outputs.region}.awstrack.me\"`,\n \"\",\n pc.dim(\n \"Note: This CNAME allows SES to rewrite links in your emails to use\"\n ),\n pc.dim(\"your custom domain for open and click tracking.\"),\n ];\n\n clack.note(trackingLines.join(\"\\n\"), \"DNS Record to add:\");\n }\n}\n\n/**\n * Status output configuration\n */\nexport type StatusOutputs = {\n integrationLevel: \"dashboard-only\" | \"enhanced\";\n region: string;\n domains: Array<{\n domain: string;\n status: \"verified\" | \"pending\" | \"failed\";\n dkimTokens?: string[];\n mailFromDomain?: string;\n mailFromStatus?: string;\n }>;\n resources: {\n roleArn?: string;\n configSetName?: string;\n tableName?: string;\n lambdaFunctions?: number;\n snsTopics?: number;\n archiveArn?: string;\n archivingEnabled?: boolean;\n archiveRetention?: string;\n };\n tracking?: {\n customTrackingDomain?: string;\n httpsEnabled?: boolean;\n cloudFrontDomain?: string;\n };\n};\n\n/**\n * Display status information\n */\nexport function displayStatus(status: StatusOutputs) {\n clack.intro(pc.bold(\"Wraps Email Infrastructure\"));\n\n const infoLines = [\n `${pc.bold(\"Integration:\")} ${pc.cyan(status.integrationLevel)}`,\n `${pc.bold(\"Region:\")} ${pc.cyan(status.region)}`,\n ];\n\n if (status.domains.length > 0) {\n const domainStrings = status.domains.map((d) => {\n const statusIcon =\n d.status === \"verified\" ? \"✓\" : d.status === \"pending\" ? \"⏱\" : \"✗\";\n const statusColor =\n d.status === \"verified\"\n ? pc.green\n : d.status === \"pending\"\n ? pc.yellow\n : pc.red;\n\n let domainLine = ` ${d.domain} ${statusColor(`${statusIcon} ${d.status}`)}`;\n\n // Add MAIL FROM domain info if configured\n if (d.mailFromDomain) {\n const mailFromStatusIcon = d.mailFromStatus === \"SUCCESS\" ? \"✓\" : \"⏱\";\n const mailFromColor =\n d.mailFromStatus === \"SUCCESS\" ? pc.green : pc.yellow;\n domainLine += `\\n ${pc.dim(\"MAIL FROM:\")} ${d.mailFromDomain} ${mailFromColor(mailFromStatusIcon)}`;\n }\n\n return domainLine;\n });\n infoLines.push(`${pc.bold(\"Domains:\")}\\n${domainStrings.join(\"\\n\")}`);\n }\n\n clack.note(infoLines.join(\"\\n\"), \"Configuration\");\n\n // Features\n const featureLines = [];\n featureLines.push(` ${pc.green(\"✓\")} Email Sending ${pc.dim(\"(via SES)\")}`);\n\n if (status.resources.tableName) {\n featureLines.push(\n ` ${pc.green(\"✓\")} Email Tracking ${pc.dim(\"(DynamoDB logs)\")}`\n );\n } else {\n featureLines.push(\n ` ${pc.dim(\"○\")} Email Tracking ${pc.dim(\"(run 'wraps email upgrade' to enable)\")}`\n );\n }\n\n if (\n status.resources.lambdaFunctions &&\n status.resources.lambdaFunctions > 0\n ) {\n featureLines.push(\n ` ${pc.green(\"✓\")} Bounce/Complaint Handling ${pc.dim(\"(automated)\")}`\n );\n } else {\n featureLines.push(\n ` ${pc.dim(\"○\")} Bounce/Complaint Handling ${pc.dim(\"(run 'wraps email upgrade' to enable)\")}`\n );\n }\n\n // Email Archiving\n if (status.resources.archivingEnabled) {\n const retentionLabel =\n {\n \"7days\": \"7 days\",\n \"30days\": \"30 days\",\n \"90days\": \"90 days\",\n \"6months\": \"6 months\",\n \"1year\": \"1 year\",\n \"18months\": \"18 months\",\n }[status.resources.archiveRetention || \"90days\"] || \"90 days\";\n featureLines.push(\n ` ${pc.green(\"✓\")} Email Archiving ${pc.dim(`(${retentionLabel} retention)`)}`\n );\n } else {\n featureLines.push(\n ` ${pc.dim(\"○\")} Email Archiving ${pc.dim(\"(run 'wraps email upgrade' to enable)\")}`\n );\n }\n\n // Custom Tracking Domain\n if (status.tracking?.customTrackingDomain) {\n const protocol = status.tracking.httpsEnabled ? \"HTTPS\" : \"HTTP\";\n const cloudFrontStatus = status.tracking.httpsEnabled\n ? status.tracking.cloudFrontDomain\n ? pc.green(\"✓ Active\")\n : pc.yellow(\"⏱ Pending\")\n : \"\";\n const trackingLabel = status.tracking.httpsEnabled\n ? `${protocol} tracking ${cloudFrontStatus}`\n : `${protocol} tracking`;\n featureLines.push(\n ` ${pc.green(\"✓\")} Custom Tracking Domain ${pc.dim(`(${trackingLabel})`)}`\n );\n featureLines.push(` ${pc.cyan(status.tracking.customTrackingDomain)}`);\n } else {\n featureLines.push(\n ` ${pc.dim(\"○\")} Custom Tracking Domain ${pc.dim(\"(run 'wraps email upgrade' to enable)\")}`\n );\n }\n\n featureLines.push(\n ` ${pc.green(\"✓\")} Console Dashboard ${pc.dim(\"(run 'wraps console')\")}`\n );\n\n clack.note(featureLines.join(\"\\n\"), \"Features\");\n\n // Resources\n const resourceLines = [];\n\n if (status.resources.roleArn) {\n resourceLines.push(\n ` ${pc.green(\"✓\")} IAM Role: ${pc.cyan(status.resources.roleArn)}`\n );\n }\n\n if (status.resources.configSetName) {\n resourceLines.push(\n ` ${pc.green(\"✓\")} Configuration Set: ${pc.cyan(status.resources.configSetName)}`\n );\n }\n\n if (status.resources.tableName) {\n resourceLines.push(\n ` ${pc.green(\"✓\")} DynamoDB Table: ${pc.cyan(status.resources.tableName)}`\n );\n }\n\n if (status.resources.lambdaFunctions) {\n resourceLines.push(\n ` ${pc.green(\"✓\")} Lambda Functions: ${pc.cyan(\n `${status.resources.lambdaFunctions} deployed`\n )}`\n );\n }\n\n if (status.resources.snsTopics) {\n resourceLines.push(\n ` ${pc.green(\"✓\")} SNS Topics: ${pc.cyan(`${status.resources.snsTopics} configured`)}`\n );\n }\n\n if (status.resources.archiveArn) {\n resourceLines.push(\n ` ${pc.green(\"✓\")} Mail Manager Archive: ${pc.cyan(status.resources.archiveArn)}`\n );\n }\n\n clack.note(resourceLines.join(\"\\n\"), \"Resources\");\n\n // Show DNS records for pending domains OR domains with pending MAIL FROM\n const domainsNeedingDNS = status.domains.filter(\n (d) =>\n (d.status === \"pending\" && d.dkimTokens) ||\n (d.mailFromDomain && d.mailFromStatus !== \"SUCCESS\")\n );\n if (domainsNeedingDNS.length > 0) {\n for (const domain of domainsNeedingDNS) {\n const dnsLines = [];\n\n // DKIM records (only for pending domains)\n if (\n domain.status === \"pending\" &&\n domain.dkimTokens &&\n domain.dkimTokens.length > 0\n ) {\n // Use MAIL FROM domain for DMARC rua if configured, otherwise use main domain\n const dmarcRuaDomain = domain.mailFromDomain || domain.domain;\n dnsLines.push(\n pc.bold(\"DKIM Records (CNAME):\"),\n ...domain.dkimTokens.map(\n (token) =>\n ` ${pc.cyan(`${token}._domainkey.${domain.domain}`)} ${pc.dim(\"CNAME\")} \"${token}.dkim.amazonses.com\"`\n ),\n \"\",\n pc.bold(\"SPF Record (TXT):\"),\n ` ${pc.cyan(domain.domain)} ${pc.dim(\"TXT\")} \"v=spf1 include:amazonses.com ~all\"`,\n pc.dim(\" Note: If you have an existing SPF record, add 'include:amazonses.com' to it\"),\n \"\",\n pc.bold(\"DMARC Record (TXT):\"),\n ` ${pc.cyan(`_dmarc.${domain.domain}`)} ${pc.dim(\"TXT\")} \"v=DMARC1; p=quarantine; rua=mailto:postmaster@${dmarcRuaDomain}\"`\n );\n }\n\n // MAIL FROM records (if configured but not verified)\n if (domain.mailFromDomain && domain.mailFromStatus !== \"SUCCESS\") {\n if (dnsLines.length > 0) {\n dnsLines.push(\"\");\n }\n dnsLines.push(\n pc.bold(\"MAIL FROM Domain Records (for DMARC alignment):\"),\n ` ${pc.cyan(domain.mailFromDomain)} ${pc.dim(\"MX\")} \"10 feedback-smtp.${status.region}.amazonses.com\"`,\n ` ${pc.cyan(domain.mailFromDomain)} ${pc.dim(\"TXT\")} \"v=spf1 include:amazonses.com ~all\"`\n );\n }\n\n if (dnsLines.length > 0) {\n clack.note(dnsLines.join(\"\\n\"), `DNS Records for ${domain.domain}`);\n }\n }\n\n // Show verify command with first domain needing DNS as example\n const exampleDomain = domainsNeedingDNS[0].domain;\n console.log(\n `\\n${pc.dim(\"Run:\")} ${pc.yellow(`wraps email verify --domain ${exampleDomain}`)} ${pc.dim(\n \"(after DNS propagates)\"\n )}\\n`\n );\n }\n\n console.log(`\\n${pc.bold(\"Dashboard:\")} ${pc.blue(\"https://app.wraps.dev\")}`);\n console.log(`${pc.bold(\"Docs:\")} ${pc.blue(\"https://wraps.dev/docs\")}\\n`);\n}\n\n/**\n * Preview output configuration\n */\nexport type PreviewOutputs = {\n changeSummary: {\n create?: number;\n update?: number;\n delete?: number;\n same?: number;\n replace?: number;\n };\n costEstimate?: string;\n commandName: string;\n};\n\n/**\n * Display preview results with resource changes and cost estimate\n */\nexport function displayPreview(outputs: PreviewOutputs): void {\n console.log(pc.yellow(\"\\n--- PREVIEW MODE (no changes will be made) ---\\n\"));\n\n // Display change summary\n const changes = outputs.changeSummary;\n const summaryLines: string[] = [];\n\n if (changes.create && changes.create > 0) {\n summaryLines.push(` ${pc.green(\"+\")} ${changes.create} to create`);\n }\n if (changes.update && changes.update > 0) {\n summaryLines.push(` ${pc.yellow(\"~\")} ${changes.update} to update`);\n }\n if (changes.delete && changes.delete > 0) {\n summaryLines.push(` ${pc.red(\"-\")} ${changes.delete} to destroy`);\n }\n if (changes.same && changes.same > 0) {\n summaryLines.push(` ${pc.dim(\"=\")} ${changes.same} unchanged`);\n }\n if (changes.replace && changes.replace > 0) {\n summaryLines.push(` ${pc.magenta(\"+-\")} ${changes.replace} to replace`);\n }\n\n if (summaryLines.length > 0) {\n clack.note(summaryLines.join(\"\\n\"), \"Resource Changes\");\n } else {\n clack.note(\"No changes detected\", \"Resource Changes\");\n }\n\n // Display cost estimate\n if (outputs.costEstimate) {\n clack.note(outputs.costEstimate, \"Estimated Monthly Cost\");\n }\n\n console.log(pc.yellow(\"\\n--- END PREVIEW (no changes were made) ---\\n\"));\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { deployEmailStack } from \"../../infrastructure/email-stack.js\";\nimport { trackCommand, trackError } from \"../../telemetry/events.js\";\nimport type {\n EmailConfigOptions,\n EmailStackConfig,\n} from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { errors } from \"../../utils/shared/errors.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n loadConnectionMetadata,\n saveConnectionMetadata,\n} from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayPreview,\n displaySuccess,\n} from \"../../utils/shared/output.js\";\nimport { ensurePulumiInstalled } from \"../../utils/shared/pulumi.js\";\n\n/**\n * Config command - Redeploy infrastructure to apply CLI updates\n * This command updates Lambda functions and other managed resources\n * without requiring configuration changes from the user.\n */\nexport async function config(options: EmailConfigOptions): Promise<void> {\n const startTime = Date.now();\n\n clack.intro(\n pc.bold(\n options.preview\n ? \"Wraps Config Preview\"\n : \"Wraps Config - Apply CLI Updates to Infrastructure\"\n )\n );\n\n const progress = new DeploymentProgress();\n\n // 1. Check Pulumi CLI is installed\n const wasAutoInstalled = await progress.execute(\n \"Checking Pulumi CLI installation\",\n async () => await ensurePulumiInstalled()\n );\n\n if (wasAutoInstalled) {\n progress.info(\"Pulumi CLI was automatically installed\");\n }\n\n // 2. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`Connected to AWS account: ${pc.cyan(identity.accountId)}`);\n\n // 3. Get region\n let region = options.region;\n if (!region) {\n const defaultRegion = await getAWSRegion();\n region = defaultRegion;\n }\n\n // 4. Load existing connection metadata\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n\n if (!metadata) {\n clack.log.error(\n `No Wraps connection found for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} to create new infrastructure or ${pc.cyan(\"wraps email connect\")} to connect existing.`\n );\n process.exit(1);\n }\n\n progress.info(`Found existing connection created: ${metadata.timestamp}`);\n\n // 5. Display current configuration\n console.log(`\\n${pc.bold(\"Current Configuration:\")}\\n`);\n\n if (metadata.services.email?.preset) {\n console.log(` Preset: ${pc.cyan(metadata.services.email?.preset)}`);\n } else {\n console.log(` Preset: ${pc.cyan(\"custom\")}`);\n }\n\n const config = metadata.services.email?.config;\n\n if (!config) {\n clack.log.error(\"No email configuration found in metadata\");\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} to create new infrastructure.`\n );\n process.exit(1);\n }\n\n // Show sending domain if configured\n if (config.domain) {\n console.log(` Sending Domain: ${pc.cyan(config.domain)}`);\n }\n\n if (config.tracking?.enabled) {\n console.log(` ${pc.green(\"✓\")} Open & Click Tracking`);\n }\n\n if (config.suppressionList?.enabled) {\n console.log(` ${pc.green(\"✓\")} Bounce/Complaint Suppression`);\n }\n\n if (config.eventTracking?.enabled) {\n console.log(` ${pc.green(\"✓\")} Event Tracking (EventBridge)`);\n }\n\n if (config.dedicatedIp) {\n console.log(` ${pc.green(\"✓\")} Dedicated IP Address`);\n }\n\n console.log(\"\");\n\n // 6. Show what will be updated\n console.log(`${pc.bold(\"What will be updated:\")}\\n`);\n console.log(\n ` ${pc.cyan(\"•\")} Lambda function code (if event tracking enabled)`\n );\n console.log(\n ` ${pc.cyan(\"•\")} EventBridge rules (if event tracking enabled)`\n );\n console.log(` ${pc.cyan(\"•\")} IAM policies (security improvements)`);\n console.log(` ${pc.cyan(\"•\")} SES configuration set (feature updates)`);\n console.log(\"\");\n\n progress.info(\n \"Your current configuration will be preserved - no features will be added or removed\"\n );\n console.log(\"\");\n\n // 7. Confirm update (skip if --yes or --preview)\n if (!(options.yes || options.preview)) {\n const confirmed = await clack.confirm({\n message: \"Proceed with update?\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel(\"Update cancelled.\");\n process.exit(0);\n }\n }\n\n // 8. Get Vercel config if needed\n let vercelConfig;\n if (metadata.provider === \"vercel\" && metadata.vercel) {\n vercelConfig = metadata.vercel;\n }\n\n // 9. Build stack configuration (reuse existing config)\n const stackConfig: EmailStackConfig = {\n provider: metadata.provider,\n region,\n vercel: vercelConfig,\n emailConfig: config,\n };\n\n // 10. Preview or Update Pulumi stack\n if (options.preview) {\n // PREVIEW MODE - show what would be updated without deploying\n try {\n const previewResult = await progress.execute(\n \"Generating update preview\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName:\n metadata.services.email?.pulumiStackName ||\n `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Refresh state to sync with AWS before previewing\n await stack.refresh({ onOutput: () => {} });\n\n // Run preview instead of deployment\n const result = await stack.preview({ diff: true });\n return result;\n }\n );\n\n // Display preview results\n displayPreview({\n changeSummary: previewResult.changeSummary,\n commandName: \"wraps email config\",\n });\n\n clack.outro(\n pc.green(\"Preview complete. Run without --preview to update.\")\n );\n\n // Track preview completion\n trackCommand(\"email:config\", {\n success: true,\n preview: true,\n duration_ms: Date.now() - startTime,\n });\n return;\n } catch (error: any) {\n trackError(\"PREVIEW_FAILED\", \"email:config\", { step: \"preview\" });\n if (error.message?.includes(\"stack is currently locked\")) {\n throw errors.stackLocked();\n }\n throw new Error(`Preview failed: ${error.message}`);\n }\n }\n\n // UPDATE MODE - actually update infrastructure\n let outputs;\n try {\n outputs = await progress.execute(\n \"Updating Wraps infrastructure (this may take 2-3 minutes)\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName:\n metadata.services.email?.pulumiStackName ||\n `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.workspace.selectStack(\n metadata.services.email?.pulumiStackName ||\n `wraps-${identity.accountId}-${region}`\n );\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Refresh state to sync with actual AWS resources (prevents AlreadyExists errors)\n await stack.refresh({ onOutput: () => {} });\n\n // Pulumi will automatically detect changes and only update what's needed\n const upResult = await stack.up({ onOutput: () => {} });\n const pulumiOutputs = upResult.outputs;\n\n return {\n roleArn: pulumiOutputs.roleArn?.value as string,\n configSetName: pulumiOutputs.configSetName?.value as\n | string\n | undefined,\n tableName: pulumiOutputs.tableName?.value as string | undefined,\n region: pulumiOutputs.region?.value as string,\n lambdaFunctions: pulumiOutputs.lambdaFunctions?.value as\n | string[]\n | undefined,\n domain: pulumiOutputs.domain?.value as string | undefined,\n dkimTokens: pulumiOutputs.dkimTokens?.value as string[] | undefined,\n customTrackingDomain: pulumiOutputs.customTrackingDomain?.value as\n | string\n | undefined,\n };\n }\n );\n } catch (error: any) {\n // Track update failure\n trackCommand(\"email:config\", {\n success: false,\n duration_ms: Date.now() - startTime,\n });\n\n // Check if it's a lock file error\n if (error.message?.includes(\"stack is currently locked\")) {\n trackError(\"STACK_LOCKED\", \"email:config\", { step: \"update\" });\n throw errors.stackLocked();\n }\n\n trackError(\"UPDATE_FAILED\", \"email:config\", { step: \"update\" });\n throw new Error(`Pulumi update failed: ${error.message}`);\n }\n\n // 11. Update metadata timestamp (config stays the same)\n metadata.timestamp = new Date().toISOString();\n await saveConnectionMetadata(metadata);\n\n progress.info(\"Connection metadata updated\");\n\n // 12. Display success message\n displaySuccess({\n roleArn: outputs.roleArn,\n configSetName: outputs.configSetName,\n region: outputs.region!,\n tableName: outputs.tableName,\n customTrackingDomain: outputs.customTrackingDomain,\n });\n\n // Show what was updated\n console.log(`\\n${pc.green(\"✓\")} ${pc.bold(\"Update complete!\")}\\n`);\n console.log(\n \"Infrastructure has been updated with the latest CLI improvements.\\n\"\n );\n console.log(`${pc.bold(\"Next steps:\")}\\n`);\n console.log(\n ` ${pc.cyan(\"1.\")} No code changes needed - your existing SDK integration continues to work`\n );\n console.log(\n ` ${pc.cyan(\"2.\")} Check ${pc.cyan(\"wraps status\")} to verify all resources are healthy`\n );\n console.log(\n ` ${pc.cyan(\"3.\")} View analytics at ${pc.cyan(\"wraps console\")}\\n`\n );\n\n // 13. Track successful update\n trackCommand(\"email:config\", {\n success: true,\n duration_ms: Date.now() - startTime,\n });\n}\n","import * as aws from \"@pulumi/aws\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport type { EmailStackConfig, StackOutputs } from \"../types/index.js\";\nimport { createDynamoDBTables } from \"./resources/dynamodb.js\";\nimport { createEventBridgeResources } from \"./resources/eventbridge.js\";\nimport { createIAMRole } from \"./resources/iam.js\";\nimport { deployLambdaFunctions } from \"./resources/lambda.js\";\nimport { createSESResources, eventDestinationExists } from \"./resources/ses.js\";\nimport { createSQSResources } from \"./resources/sqs.js\";\nimport { createVercelOIDC } from \"./vercel-oidc.js\";\n\n/**\n * Deploy email infrastructure stack using Pulumi\n */\nexport async function deployEmailStack(\n config: EmailStackConfig\n): Promise<StackOutputs> {\n // Get current AWS account\n const identity = await aws.getCallerIdentity();\n const accountId = identity.accountId;\n\n let oidcProvider: aws.iam.OpenIdConnectProvider | undefined;\n\n // 1. Create OIDC provider if Vercel\n if (config.provider === \"vercel\" && config.vercel) {\n oidcProvider = await createVercelOIDC({\n teamSlug: config.vercel.teamSlug,\n accountId,\n });\n }\n\n const emailConfig = config.emailConfig;\n\n // 2. Create IAM role\n const role = await createIAMRole({\n provider: config.provider,\n oidcProvider,\n vercelTeamSlug: config.vercel?.teamSlug,\n vercelProjectName: config.vercel?.projectName,\n emailConfig,\n });\n\n // 3. CloudFront + ACM (if HTTPS tracking enabled)\n let cloudFrontResources;\n let acmResources;\n\n if (\n emailConfig.tracking?.enabled &&\n emailConfig.tracking.customRedirectDomain &&\n emailConfig.tracking.httpsEnabled\n ) {\n // Check for Route53 hosted zone (for automatic DNS validation)\n const { findHostedZone } = await import(\"../utils/email/route53.js\");\n const hostedZone = await findHostedZone(\n emailConfig.tracking.customRedirectDomain,\n config.region\n );\n\n // Create ACM certificate (in us-east-1 for CloudFront)\n const { createACMCertificate } = await import(\"./resources/acm.js\");\n acmResources = await createACMCertificate({\n domain: emailConfig.tracking.customRedirectDomain,\n hostedZoneId: hostedZone?.id,\n });\n\n // Create CloudFront distribution with SSL certificate\n // Import CloudFront creation function\n const { createCloudFrontTracking } = await import(\n \"./resources/cloudfront.js\"\n );\n\n // Determine which certificate ARN to use:\n // - Route53: Use certificateValidation.certificateArn (waits for validation)\n // - Manual DNS: Use certificate.arn directly (CloudFront will fail if not validated)\n const certificateArn = acmResources.certificateValidation\n ? acmResources.certificateValidation.certificateArn\n : acmResources.certificate.arn;\n\n cloudFrontResources = await createCloudFrontTracking({\n customTrackingDomain: emailConfig.tracking.customRedirectDomain,\n region: config.region,\n certificateArn,\n hostedZoneId: hostedZone?.id, // Pass hosted zone ID for automatic DNS record creation\n });\n }\n\n // 4. SES resources (if tracking or event tracking enabled)\n let sesResources;\n if (emailConfig.tracking?.enabled || emailConfig.eventTracking?.enabled) {\n // Check if the event destination already exists in AWS but not in Pulumi state\n // This can happen if resources were created outside Pulumi or state got out of sync\n const shouldImportEventDest =\n emailConfig.eventTracking?.enabled &&\n (await eventDestinationExists(\n \"wraps-email-tracking\",\n \"wraps-email-eventbridge\",\n config.region\n ));\n\n // Compute mailFromDomain from mailFromSubdomain if provided\n let mailFromDomain = emailConfig.mailFromDomain;\n if (!mailFromDomain && emailConfig.mailFromSubdomain && emailConfig.domain) {\n mailFromDomain = `${emailConfig.mailFromSubdomain}.${emailConfig.domain}`;\n }\n\n sesResources = await createSESResources({\n domain: emailConfig.domain,\n mailFromDomain,\n region: config.region,\n trackingConfig: emailConfig.tracking,\n eventTypes: emailConfig.eventTracking?.events,\n eventTrackingEnabled: emailConfig.eventTracking?.enabled, // Pass flag to create EventBridge destination\n tlsRequired: emailConfig.tlsRequired, // Require TLS encryption for all emails\n importExistingEventDestination: shouldImportEventDest, // Import if exists to avoid AlreadyExistsException\n });\n }\n\n // 5. DynamoDB tables (if history storage enabled)\n let dynamoTables;\n if (emailConfig.eventTracking?.dynamoDBHistory) {\n dynamoTables = await createDynamoDBTables({\n retention: emailConfig.eventTracking.archiveRetention,\n });\n }\n\n // 6. SQS queues (if event tracking enabled)\n let sqsResources;\n if (emailConfig.eventTracking?.enabled) {\n sqsResources = await createSQSResources();\n }\n\n // 7. EventBridge rule to route SES events to SQS (if event tracking enabled)\n if (emailConfig.eventTracking?.enabled && sesResources && sqsResources) {\n await createEventBridgeResources({\n eventBusArn: sesResources.eventBus.arn,\n queueArn: sqsResources.queue.arn,\n queueUrl: sqsResources.queue.url,\n });\n }\n\n // 8. Lambda functions (if event tracking and DynamoDB enabled)\n let lambdaFunctions;\n if (\n emailConfig.eventTracking?.dynamoDBHistory &&\n dynamoTables &&\n sqsResources\n ) {\n lambdaFunctions = await deployLambdaFunctions({\n roleArn: role.arn,\n tableName: dynamoTables.emailHistory.name,\n queueArn: sqsResources.queue.arn,\n accountId,\n region: config.region,\n });\n }\n\n // 9. Mail Manager Archive (if email archiving enabled)\n let archiveResources;\n if (emailConfig.emailArchiving?.enabled && sesResources) {\n const { createMailManagerArchive } = await import(\n \"./resources/mail-manager.js\"\n );\n archiveResources = await createMailManagerArchive({\n name: \"email\",\n retention: emailConfig.emailArchiving.retention,\n configSetName: sesResources.configSet.configurationSetName,\n region: config.region,\n });\n }\n\n // Return outputs\n return {\n roleArn: role.arn as any as string,\n configSetName: sesResources?.configSet.configurationSetName as any as\n | string\n | undefined,\n tableName: dynamoTables?.emailHistory.name as any as string | undefined,\n region: config.region,\n lambdaFunctions: lambdaFunctions\n ? [lambdaFunctions.eventProcessor.arn as any as string]\n : undefined,\n domain: emailConfig.domain,\n dkimTokens: sesResources?.dkimTokens as any as string[] | undefined,\n dnsAutoCreated: sesResources?.dnsAutoCreated,\n eventBusName: sesResources?.eventBus.name as any as string | undefined,\n queueUrl: sqsResources?.queue.url as any as string | undefined,\n dlqUrl: sqsResources?.dlq.url as any as string | undefined,\n customTrackingDomain: sesResources?.customTrackingDomain,\n httpsTrackingEnabled: emailConfig.tracking?.httpsEnabled,\n cloudFrontDomain: cloudFrontResources?.domainName as any as\n | string\n | undefined,\n acmCertificateValidationRecords: acmResources?.validationRecords as any as\n | Array<{ name: string; type: string; value: string }>\n | undefined,\n mailFromDomain: sesResources?.mailFromDomain,\n archiveArn: archiveResources?.archiveArn,\n archivingEnabled: emailConfig.emailArchiving?.enabled,\n archiveRetention: emailConfig.emailArchiving?.enabled\n ? emailConfig.emailArchiving.retention\n : undefined,\n };\n}\n\n/**\n * Run Pulumi program inline\n */\nexport async function runPulumiProgram(\n stackName: string,\n program: () => Promise<StackOutputs>\n): Promise<StackOutputs> {\n const stack = await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName,\n projectName: \"wraps-email\",\n program,\n },\n {\n workDir: `${process.env.HOME}/.wraps/pulumi`,\n }\n );\n\n // Set AWS region\n await stack.setConfig(\"aws:region\", { value: \"us-east-1\" });\n\n // Run the deployment\n const upResult = await stack.up({\n onOutput: (msg) => process.stdout.write(msg),\n });\n\n // Get outputs\n const outputs = upResult.outputs;\n\n return {\n roleArn: outputs.roleArn?.value as string,\n configSetName: outputs.configSetName?.value as string | undefined,\n tableName: outputs.tableName?.value as string | undefined,\n region: outputs.region?.value as string,\n };\n}\n","import * as aws from \"@pulumi/aws\";\nimport type { ArchiveRetention } from \"../../types/index.js\";\n\n/**\n * DynamoDB configuration\n */\nexport type DynamoDBConfig = {\n retention?: ArchiveRetention;\n};\n\n/**\n * DynamoDB tables output\n */\nexport type DynamoDBTables = {\n emailHistory: aws.dynamodb.Table;\n};\n\n/**\n * Check if DynamoDB table exists\n */\nasync function tableExists(tableName: string): Promise<boolean> {\n try {\n const { DynamoDBClient, DescribeTableCommand } = await import(\n \"@aws-sdk/client-dynamodb\"\n );\n const dynamodb = new DynamoDBClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n\n await dynamodb.send(new DescribeTableCommand({ TableName: tableName }));\n return true;\n } catch (error: any) {\n if (error.name === \"ResourceNotFoundException\") {\n return false;\n }\n console.error(\"Error checking for existing DynamoDB table:\", error);\n return false;\n }\n}\n\n/**\n * Create DynamoDB tables for email tracking\n */\nexport async function createDynamoDBTables(\n _config?: DynamoDBConfig\n): Promise<DynamoDBTables> {\n // Check if table already exists\n const tableName = \"wraps-email-history\";\n const exists = await tableExists(tableName);\n\n // Email history table (TTL is set based on retention in Lambda via expiresAt field)\n // Note: retention config is passed but TTL is actually managed by Lambda setting expiresAt\n const emailHistory = exists\n ? new aws.dynamodb.Table(\n tableName,\n {\n name: tableName,\n billingMode: \"PAY_PER_REQUEST\",\n hashKey: \"messageId\",\n rangeKey: \"sentAt\",\n attributes: [\n { name: \"messageId\", type: \"S\" },\n { name: \"sentAt\", type: \"N\" },\n { name: \"accountId\", type: \"S\" },\n ],\n globalSecondaryIndexes: [\n {\n name: \"accountId-sentAt-index\",\n hashKey: \"accountId\",\n rangeKey: \"sentAt\",\n projectionType: \"ALL\",\n },\n ],\n ttl: {\n enabled: true,\n attributeName: \"expiresAt\",\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n },\n },\n {\n import: tableName, // Import existing table\n }\n )\n : new aws.dynamodb.Table(tableName, {\n name: tableName,\n billingMode: \"PAY_PER_REQUEST\",\n hashKey: \"messageId\",\n rangeKey: \"sentAt\",\n attributes: [\n { name: \"messageId\", type: \"S\" },\n { name: \"sentAt\", type: \"N\" },\n { name: \"accountId\", type: \"S\" },\n ],\n globalSecondaryIndexes: [\n {\n name: \"accountId-sentAt-index\",\n hashKey: \"accountId\",\n rangeKey: \"sentAt\",\n projectionType: \"ALL\",\n },\n ],\n ttl: {\n enabled: true,\n attributeName: \"expiresAt\",\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n },\n });\n\n return {\n emailHistory,\n };\n}\n","import * as aws from \"@pulumi/aws\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\n/**\n * EventBridge resources configuration\n */\nexport type EventBridgeConfig = {\n eventBusArn: pulumi.Output<string>;\n queueArn: pulumi.Output<string>;\n queueUrl: pulumi.Output<string>;\n};\n\n/**\n * EventBridge resources output\n */\nexport type EventBridgeResources = {\n rule: aws.cloudwatch.EventRule;\n target: aws.cloudwatch.EventTarget;\n};\n\n/**\n * Create EventBridge rule to route SES events to SQS queue\n *\n * This rule captures all SES events from the default event bus\n * and routes them to the SQS queue for processing.\n *\n * Note: SES can only send to the default EventBridge bus, not custom buses.\n */\nexport async function createEventBridgeResources(\n config: EventBridgeConfig\n): Promise<EventBridgeResources> {\n // Extract event bus name from ARN (will be \"default\" for SES)\n const eventBusName = config.eventBusArn.apply((arn) => arn.split(\"/\").pop()!);\n\n // EventBridge rule to capture all SES events on default bus\n const rule = new aws.cloudwatch.EventRule(\"wraps-email-events-rule\", {\n name: \"wraps-email-events-to-sqs\",\n description: \"Route all SES email events to SQS for processing\",\n eventBusName,\n eventPattern: JSON.stringify({\n source: [\"aws.ses\"],\n // SES sends events with various detail-types based on event type\n // We capture all by not filtering on detail-type\n }),\n tags: {\n ManagedBy: \"wraps-cli\",\n },\n });\n\n // SQS queue policy to allow EventBridge to send messages\n new aws.sqs.QueuePolicy(\"wraps-email-events-queue-policy\", {\n queueUrl: config.queueUrl,\n policy: pulumi\n .all([config.queueArn, rule.arn])\n .apply(([queueArn, ruleArn]) =>\n JSON.stringify({\n Version: \"2012-10-17\",\n Statement: [\n {\n Effect: \"Allow\",\n Principal: {\n Service: \"events.amazonaws.com\",\n },\n Action: \"sqs:SendMessage\",\n Resource: queueArn,\n Condition: {\n ArnEquals: {\n \"aws:SourceArn\": ruleArn,\n },\n },\n },\n ],\n })\n ),\n });\n\n // EventBridge target to send events to SQS\n const target = new aws.cloudwatch.EventTarget(\"wraps-email-events-target\", {\n rule: rule.name,\n eventBusName,\n arn: config.queueArn,\n });\n\n return {\n rule,\n target,\n };\n}\n","import * as aws from \"@pulumi/aws\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport type { Provider, WrapsEmailConfig } from \"../../types/index.js\";\n\n/**\n * IAM role configuration\n */\nexport type IAMRoleConfig = {\n provider: Provider;\n oidcProvider?: aws.iam.OpenIdConnectProvider;\n vercelTeamSlug?: string;\n vercelProjectName?: string;\n emailConfig: WrapsEmailConfig;\n};\n\n/**\n * Check if IAM role exists\n */\nasync function roleExists(roleName: string): Promise<boolean> {\n try {\n const { IAMClient, GetRoleCommand } = await import(\"@aws-sdk/client-iam\");\n // IAM is global but SDK still requires a region\n const iam = new IAMClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n\n await iam.send(new GetRoleCommand({ RoleName: roleName }));\n return true;\n } catch (error: any) {\n if (error.name === \"NoSuchEntityException\") {\n return false;\n }\n console.error(\"Error checking for existing IAM role:\", error);\n return false;\n }\n}\n\n/**\n * Create IAM role for email infrastructure\n */\nexport async function createIAMRole(\n config: IAMRoleConfig\n): Promise<aws.iam.Role> {\n // Build assume role policy based on provider\n let assumeRolePolicy: pulumi.Output<string>;\n\n if (config.provider === \"vercel\" && config.oidcProvider) {\n assumeRolePolicy = pulumi.interpolate`{\n \"Version\": \"2012-10-17\",\n \"Statement\": [{\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Federated\": \"${config.oidcProvider.arn}\"\n },\n \"Action\": \"sts:AssumeRoleWithWebIdentity\",\n \"Condition\": {\n \"StringEquals\": {\n \"oidc.vercel.com/${config.vercelTeamSlug}:aud\": \"https://vercel.com/${config.vercelTeamSlug}\"\n },\n \"StringLike\": {\n \"oidc.vercel.com/${config.vercelTeamSlug}:sub\": \"owner:${config.vercelTeamSlug}:project:${config.vercelProjectName}:environment:*\"\n }\n }\n }]\n }`;\n } else if (config.provider === \"aws\") {\n // Native AWS - EC2, Lambda, ECS can assume\n assumeRolePolicy = pulumi.output(`{\n \"Version\": \"2012-10-17\",\n \"Statement\": [{\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Service\": [\"lambda.amazonaws.com\", \"ec2.amazonaws.com\", \"ecs-tasks.amazonaws.com\"]\n },\n \"Action\": \"sts:AssumeRole\"\n }]\n }`);\n } else {\n // Other providers - will use access keys\n throw new Error(\"Other providers not yet implemented\");\n }\n\n // Check if role already exists\n const roleName = \"wraps-email-role\";\n const exists = await roleExists(roleName);\n\n const role = exists\n ? new aws.iam.Role(\n roleName,\n {\n name: roleName,\n assumeRolePolicy,\n tags: {\n ManagedBy: \"wraps-cli\",\n Provider: config.provider,\n },\n },\n {\n import: roleName, // Import existing role (use role name, not ARN)\n }\n )\n : new aws.iam.Role(roleName, {\n name: roleName,\n assumeRolePolicy,\n tags: {\n ManagedBy: \"wraps-cli\",\n Provider: config.provider,\n },\n });\n\n // Build policy statements based on enabled features\n const statements: any[] = [];\n\n // Always allow reading SES metrics for dashboard\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"ses:GetSendStatistics\",\n \"ses:ListIdentities\",\n \"ses:GetIdentityVerificationAttributes\",\n \"cloudwatch:GetMetricData\",\n \"cloudwatch:GetMetricStatistics\",\n ],\n Resource: \"*\",\n });\n\n // Allow sending if enabled\n if (config.emailConfig.sendingEnabled !== false) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"ses:SendEmail\",\n \"ses:SendRawEmail\",\n \"ses:SendTemplatedEmail\",\n \"ses:SendBulkTemplatedEmail\",\n ],\n Resource: \"*\",\n });\n }\n\n // Allow DynamoDB access if history storage enabled\n if (config.emailConfig.eventTracking?.dynamoDBHistory) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"dynamodb:PutItem\",\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n \"dynamodb:Scan\",\n \"dynamodb:BatchGetItem\",\n \"dynamodb:DescribeTable\",\n ],\n Resource: [\n \"arn:aws:dynamodb:*:*:table/wraps-email-*\",\n \"arn:aws:dynamodb:*:*:table/wraps-email-*/index/*\",\n ],\n });\n }\n\n // Allow EventBridge access if event tracking enabled\n if (config.emailConfig.eventTracking?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\"events:PutEvents\", \"events:DescribeEventBus\"],\n Resource: \"arn:aws:events:*:*:event-bus/wraps-email-*\",\n });\n }\n\n // Allow SQS access if event tracking enabled\n if (config.emailConfig.eventTracking?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"sqs:SendMessage\",\n \"sqs:ReceiveMessage\",\n \"sqs:DeleteMessage\",\n \"sqs:GetQueueAttributes\",\n ],\n Resource: \"arn:aws:sqs:*:*:wraps-email-*\",\n });\n }\n\n // Allow Mail Manager Archive access if email archiving enabled\n if (config.emailConfig.emailArchiving?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n // Archive search operations\n \"ses:StartArchiveSearch\",\n \"ses:GetArchiveSearchResults\",\n // Archive message retrieval\n \"ses:GetArchiveMessage\",\n \"ses:GetArchiveMessageContent\",\n // Archive metadata\n \"ses:GetArchive\",\n \"ses:ListArchives\",\n // Archive export (for future use)\n \"ses:StartArchiveExport\",\n \"ses:GetArchiveExport\",\n ],\n Resource: \"arn:aws:ses:*:*:mailmanager-archive/*\",\n });\n }\n\n // Attach policy to role\n new aws.iam.RolePolicy(\"wraps-email-policy\", {\n role: role.name,\n policy: JSON.stringify({\n Version: \"2012-10-17\",\n Statement: statements,\n }),\n });\n\n return role;\n}\n","import { randomBytes } from \"node:crypto\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as aws from \"@pulumi/aws\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport { build } from \"esbuild\";\n\n/**\n * Get the package root directory (where package.json lives)\n * Works both in development (src/) and production (dist/)\n */\nfunction getPackageRoot(): string {\n const currentFile = fileURLToPath(import.meta.url);\n let dir = dirname(currentFile);\n\n // Walk up the directory tree until we find package.json\n while (dir !== dirname(dir)) {\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n dir = dirname(dir);\n }\n\n throw new Error(\"Could not find package.json\");\n}\n\n/**\n * Lambda configuration\n */\nexport type LambdaConfig = {\n roleArn: pulumi.Output<string>;\n tableName: pulumi.Output<string>;\n queueArn: pulumi.Output<string>;\n accountId: string;\n region: string;\n};\n\n/**\n * Lambda functions output\n */\nexport type LambdaFunctions = {\n eventProcessor: aws.lambda.Function;\n eventSourceMapping: aws.lambda.EventSourceMapping;\n};\n\n/**\n * Check if Lambda function exists\n */\nasync function lambdaFunctionExists(functionName: string): Promise<boolean> {\n try {\n const { LambdaClient, GetFunctionCommand } = await import(\n \"@aws-sdk/client-lambda\"\n );\n const lambda = new LambdaClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n\n await lambda.send(new GetFunctionCommand({ FunctionName: functionName }));\n return true;\n } catch (error: any) {\n if (error.name === \"ResourceNotFoundException\") {\n return false;\n }\n console.error(\"Error checking for existing Lambda function:\", error);\n return false;\n }\n}\n\n/**\n * Find existing event source mapping for Lambda function and SQS queue\n */\nasync function findEventSourceMapping(\n functionName: string,\n queueArn: string\n): Promise<string | null> {\n try {\n const { LambdaClient, ListEventSourceMappingsCommand } = await import(\n \"@aws-sdk/client-lambda\"\n );\n const lambda = new LambdaClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n\n const response = await lambda.send(\n new ListEventSourceMappingsCommand({\n FunctionName: functionName,\n EventSourceArn: queueArn,\n })\n );\n\n // Return UUID of the first matching event source mapping\n return response.EventSourceMappings?.[0]?.UUID || null;\n } catch (error: any) {\n console.error(\"Error finding event source mapping:\", error);\n return null;\n }\n}\n\n/**\n * Get the Lambda function code directory\n *\n * In production (published package), uses pre-bundled code from dist/lambda/\n * In development, bundles the TypeScript source on-the-fly\n */\nasync function getLambdaCode(functionName: string): Promise<string> {\n const packageRoot = getPackageRoot();\n\n // Check for pre-bundled Lambda code in dist/ (production - published package)\n const distLambdaPath = join(packageRoot, \"dist\", \"lambda\", functionName);\n const distBundleMarker = join(distLambdaPath, \".bundled\");\n\n if (existsSync(distBundleMarker)) {\n // Use pre-bundled code from dist/\n return distLambdaPath;\n }\n\n // Check for pre-bundled Lambda code in lambda/ (development build)\n const lambdaPath = join(packageRoot, \"lambda\", functionName);\n const lambdaBundleMarker = join(lambdaPath, \".bundled\");\n\n if (existsSync(lambdaBundleMarker)) {\n // Use pre-bundled code from lambda/\n return lambdaPath;\n }\n\n // Development mode: bundle on-the-fly from TypeScript source\n const sourcePath = join(lambdaPath, \"index.ts\");\n\n if (!existsSync(sourcePath)) {\n throw new Error(\n `Lambda source not found: ${sourcePath}\\n` +\n `This usually means the build process didn't complete successfully.\\n` +\n \"Try running: pnpm build\"\n );\n }\n\n const buildId = randomBytes(8).toString(\"hex\");\n const outdir = join(tmpdir(), `wraps-lambda-${buildId}`);\n\n if (!existsSync(outdir)) {\n mkdirSync(outdir, { recursive: true });\n }\n\n // Bundle with esbuild\n await build({\n entryPoints: [sourcePath],\n bundle: true,\n platform: \"node\",\n target: \"node24\",\n format: \"esm\",\n outfile: join(outdir, \"index.mjs\"),\n external: [\"@aws-sdk/*\"], // AWS SDK v3 is included in Lambda runtime\n minify: true,\n sourcemap: false,\n });\n\n return outdir;\n}\n\n/**\n * Deploy Lambda functions for email event processing\n *\n * Architecture:\n * SQS Queue -> Lambda (event-processor) -> DynamoDB\n *\n * The Lambda function is triggered by SQS via Event Source Mapping.\n * Failed messages are automatically sent to the DLQ after 3 retries.\n */\nexport async function deployLambdaFunctions(\n config: LambdaConfig\n): Promise<LambdaFunctions> {\n // Get Lambda code directory (pre-bundled in production, bundled on-the-fly in dev)\n const eventProcessorCode = await getLambdaCode(\"event-processor\");\n\n // IAM role for Lambda execution\n const lambdaRole = new aws.iam.Role(\"wraps-email-lambda-role\", {\n assumeRolePolicy: JSON.stringify({\n Version: \"2012-10-17\",\n Statement: [\n {\n Effect: \"Allow\",\n Principal: { Service: \"lambda.amazonaws.com\" },\n Action: \"sts:AssumeRole\",\n },\n ],\n }),\n tags: {\n ManagedBy: \"wraps-cli\",\n },\n });\n\n // Attach basic Lambda execution policy\n new aws.iam.RolePolicyAttachment(\"wraps-email-lambda-basic-execution\", {\n role: lambdaRole.name,\n policyArn:\n \"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole\",\n });\n\n // Lambda policy for DynamoDB and SQS\n new aws.iam.RolePolicy(\"wraps-email-lambda-policy\", {\n role: lambdaRole.name,\n policy: pulumi\n .all([config.tableName, config.queueArn])\n .apply(([tableName, queueArn]) =>\n JSON.stringify({\n Version: \"2012-10-17\",\n Statement: [\n {\n // DynamoDB access\n Effect: \"Allow\",\n Action: [\n \"dynamodb:PutItem\",\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n \"dynamodb:Scan\",\n \"dynamodb:UpdateItem\",\n ],\n Resource: [\n `arn:aws:dynamodb:*:*:table/${tableName}`,\n `arn:aws:dynamodb:*:*:table/${tableName}/index/*`,\n ],\n },\n {\n // SQS access for event source mapping\n Effect: \"Allow\",\n Action: [\n \"sqs:ReceiveMessage\",\n \"sqs:DeleteMessage\",\n \"sqs:GetQueueAttributes\",\n ],\n Resource: queueArn,\n },\n ],\n })\n ),\n });\n\n // Check if Lambda function already exists\n const functionName = \"wraps-email-event-processor\";\n const exists = await lambdaFunctionExists(functionName);\n\n // Create event-processor Lambda\n const eventProcessor = exists\n ? new aws.lambda.Function(\n functionName,\n {\n name: functionName,\n runtime: \"nodejs24.x\",\n handler: \"index.handler\",\n role: lambdaRole.arn,\n code: new pulumi.asset.FileArchive(eventProcessorCode),\n timeout: 300, // 5 minutes (matches SQS visibility timeout)\n memorySize: 512,\n environment: {\n variables: {\n TABLE_NAME: config.tableName,\n AWS_ACCOUNT_ID: config.accountId,\n },\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n Description:\n \"Process SES email events from SQS and store in DynamoDB\",\n },\n },\n {\n import: functionName, // Import existing function\n }\n )\n : new aws.lambda.Function(functionName, {\n name: functionName,\n runtime: \"nodejs24.x\",\n handler: \"index.handler\",\n role: lambdaRole.arn,\n code: new pulumi.asset.FileArchive(eventProcessorCode),\n timeout: 300, // 5 minutes (matches SQS visibility timeout)\n memorySize: 512,\n environment: {\n variables: {\n TABLE_NAME: config.tableName,\n AWS_ACCOUNT_ID: config.accountId,\n },\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n Description:\n \"Process SES email events from SQS and store in DynamoDB\",\n },\n });\n\n // Check if event source mapping already exists\n // Construct the queue ARN from the known queue name, region, and account ID\n const queueArnValue = `arn:aws:sqs:${config.region}:${config.accountId}:wraps-email-events`;\n const existingMappingUuid = await findEventSourceMapping(\n functionName,\n queueArnValue\n );\n\n // Create SQS event source mapping for Lambda\n // This automatically polls SQS and invokes the Lambda function\n const mappingConfig = {\n eventSourceArn: config.queueArn,\n functionName: eventProcessor.name,\n batchSize: 10, // Process up to 10 messages per invocation\n maximumBatchingWindowInSeconds: 5, // Wait up to 5 seconds to batch messages\n functionResponseTypes: [\"ReportBatchItemFailures\"], // Enable partial batch responses\n };\n\n const eventSourceMapping = existingMappingUuid\n ? new aws.lambda.EventSourceMapping(\n \"wraps-email-event-source-mapping\",\n mappingConfig,\n {\n import: existingMappingUuid, // Import with the UUID\n }\n )\n : new aws.lambda.EventSourceMapping(\n \"wraps-email-event-source-mapping\",\n mappingConfig\n );\n\n return {\n eventProcessor,\n eventSourceMapping,\n };\n}\n","import * as aws from \"@pulumi/aws\";\nimport type { SESEventType } from \"../../types/index.js\";\n\n/**\n * SES resources configuration\n */\nexport type SESResourcesConfig = {\n domain?: string;\n mailFromDomain?: string;\n region: string;\n trackingConfig?: {\n enabled: boolean;\n opens?: boolean;\n clicks?: boolean;\n customRedirectDomain?: string;\n httpsEnabled?: boolean;\n };\n eventTypes?: SESEventType[];\n eventTrackingEnabled?: boolean; // NEW: Whether to create EventBridge event destination\n tlsRequired?: boolean; // Require TLS encryption for all emails\n importExistingEventDestination?: boolean; // Import existing event destination if it exists\n};\n\n/**\n * Check if SES configuration set exists\n */\nasync function configurationSetExists(\n configSetName: string,\n region: string\n): Promise<boolean> {\n try {\n const { SESv2Client, GetConfigurationSetCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n const ses = new SESv2Client({ region });\n\n await ses.send(\n new GetConfigurationSetCommand({ ConfigurationSetName: configSetName })\n );\n return true;\n } catch (error: any) {\n if (error.name === \"NotFoundException\") {\n return false;\n }\n console.error(\"Error checking for existing configuration set:\", error);\n return false;\n }\n}\n\n/**\n * Check if event destination exists for a configuration set\n */\nexport async function eventDestinationExists(\n configSetName: string,\n eventDestName: string,\n region: string\n): Promise<boolean> {\n try {\n const { SESv2Client, GetConfigurationSetEventDestinationsCommand } =\n await import(\"@aws-sdk/client-sesv2\");\n const ses = new SESv2Client({ region });\n\n const response = await ses.send(\n new GetConfigurationSetEventDestinationsCommand({\n ConfigurationSetName: configSetName,\n })\n );\n\n return (\n response.EventDestinations?.some((dest) => dest.Name === eventDestName) ??\n false\n );\n } catch (error: any) {\n if (error.name === \"NotFoundException\") {\n return false;\n }\n // Silently return false on other errors - we'll try to create and handle errors there\n return false;\n }\n}\n\n/**\n * Check if email identity exists\n */\nasync function emailIdentityExists(\n emailIdentity: string,\n region: string\n): Promise<boolean> {\n try {\n const { SESv2Client, GetEmailIdentityCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n const ses = new SESv2Client({ region });\n\n await ses.send(\n new GetEmailIdentityCommand({ EmailIdentity: emailIdentity })\n );\n return true;\n } catch (error: any) {\n if (error.name === \"NotFoundException\") {\n return false;\n }\n console.error(\"Error checking for existing email identity:\", error);\n return false;\n }\n}\n\n/**\n * SES resources output\n */\nexport type SESResources = {\n configSet: aws.sesv2.ConfigurationSet;\n eventBus: aws.cloudwatch.EventBus;\n domainIdentity?: aws.sesv2.EmailIdentity;\n dkimTokens?: string[];\n dnsAutoCreated?: boolean;\n customTrackingDomain?: string;\n mailFromDomain?: string;\n};\n\n/**\n * Create SES resources (configuration set, EventBridge event bus, domain identity)\n */\nexport async function createSESResources(\n config: SESResourcesConfig\n): Promise<SESResources> {\n // Configuration set for tracking (using SESv2 which supports tags)\n const configSetOptions: aws.sesv2.ConfigurationSetArgs = {\n configurationSetName: \"wraps-email-tracking\",\n deliveryOptions: config.tlsRequired\n ? {\n tlsPolicy: \"REQUIRE\", // Require TLS 1.2+ for all emails\n }\n : undefined,\n suppressionOptions: {\n // Automatically suppress hard bounces and complaints at the configuration set level\n // This provides protection even if account-level suppression isn't configured\n suppressedReasons: [\"BOUNCE\", \"COMPLAINT\"],\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n Description: \"Wraps email tracking configuration set\",\n },\n };\n\n // Add custom tracking domain if provided\n // Note: The tracking domain only needs a CNAME DNS record\n // - Without HTTPS: CNAME points to r.{region}.awstrack.me\n // - With HTTPS: CNAME points to CloudFront distribution domain\n if (config.trackingConfig?.customRedirectDomain) {\n configSetOptions.trackingOptions = {\n customRedirectDomain: config.trackingConfig.customRedirectDomain,\n // HTTPS policy depends on whether HTTPS tracking is enabled\n // - REQUIRE: When using CloudFront with SSL certificate\n // - OPTIONAL: When using direct SES tracking endpoint (no SSL)\n httpsPolicy: config.trackingConfig.httpsEnabled ? \"REQUIRE\" : \"OPTIONAL\",\n };\n }\n\n // Check if configuration set already exists\n const configSetName = \"wraps-email-tracking\";\n const exists = await configurationSetExists(configSetName, config.region);\n\n const configSet = exists\n ? new aws.sesv2.ConfigurationSet(configSetName, configSetOptions, {\n import: configSetName, // Import existing configuration set\n })\n : new aws.sesv2.ConfigurationSet(configSetName, configSetOptions);\n\n // SES can only send to the default EventBridge bus\n // We'll use EventBridge rules to route from default bus to SQS\n // Get the default event bus (it always exists)\n const defaultEventBus = aws.cloudwatch.getEventBusOutput({\n name: \"default\",\n });\n\n // Event destination for all SES events -> EventBridge (default bus)\n // Only create if event tracking is enabled\n if (config.eventTrackingEnabled) {\n const eventDestName = \"wraps-email-eventbridge\";\n\n new aws.sesv2.ConfigurationSetEventDestination(\n \"wraps-email-all-events\",\n {\n configurationSetName: configSet.configurationSetName,\n eventDestinationName: eventDestName,\n eventDestination: {\n enabled: true,\n matchingEventTypes: [\n \"SEND\",\n \"DELIVERY\",\n \"OPEN\",\n \"CLICK\",\n \"BOUNCE\",\n \"COMPLAINT\",\n \"REJECT\",\n \"RENDERING_FAILURE\",\n \"DELIVERY_DELAY\",\n \"SUBSCRIPTION\",\n ],\n eventBridgeDestination: {\n // SES requires default bus - cannot use custom bus\n eventBusArn: defaultEventBus.arn,\n },\n },\n },\n {\n // Import existing resource if it already exists in AWS\n // This prevents AlreadyExistsException when the resource exists but isn't in Pulumi state\n import: config.importExistingEventDestination\n ? `wraps-email-tracking|${eventDestName}`\n : undefined,\n }\n );\n }\n\n // Optional: Verify domain if provided\n let domainIdentity: aws.sesv2.EmailIdentity | undefined;\n let dkimTokens: string[] | undefined;\n let mailFromDomain: string | undefined;\n\n if (config.domain) {\n // Check if email identity already exists\n const identityExists = await emailIdentityExists(\n config.domain,\n config.region\n );\n\n // Use SES v2 API to create email identity with configuration set\n domainIdentity = identityExists\n ? new aws.sesv2.EmailIdentity(\n \"wraps-email-domain\",\n {\n emailIdentity: config.domain,\n configurationSetName: configSet.configurationSetName, // Link configuration set to domain\n dkimSigningAttributes: {\n nextSigningKeyLength: \"RSA_2048_BIT\",\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n },\n },\n {\n import: config.domain, // Import existing identity\n }\n )\n : new aws.sesv2.EmailIdentity(\"wraps-email-domain\", {\n emailIdentity: config.domain,\n configurationSetName: configSet.configurationSetName, // Link configuration set to domain\n dkimSigningAttributes: {\n nextSigningKeyLength: \"RSA_2048_BIT\",\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n },\n });\n\n // Extract DKIM tokens for DNS configuration\n dkimTokens = domainIdentity.dkimSigningAttributes.apply(\n (attrs) => attrs?.tokens || []\n ) as any;\n\n // Configure MAIL FROM domain for better DMARC alignment (only if explicitly configured)\n if (config.mailFromDomain) {\n mailFromDomain = config.mailFromDomain;\n\n // Create/update MAIL FROM attributes\n // Note: This resource doesn't support import, but it will update existing config\n new aws.sesv2.EmailIdentityMailFromAttributes(\n \"wraps-email-mail-from\",\n {\n emailIdentity: config.domain,\n mailFromDomain,\n behaviorOnMxFailure: \"USE_DEFAULT_VALUE\", // Fallback to amazonses.com if MX record fails\n },\n {\n dependsOn: [domainIdentity], // Ensure domain identity exists first\n }\n );\n }\n }\n\n return {\n configSet,\n eventBus: defaultEventBus as any, // Return default bus reference\n domainIdentity,\n dkimTokens,\n dnsAutoCreated: false, // Will be set after deployment\n customTrackingDomain: config.trackingConfig?.customRedirectDomain,\n mailFromDomain,\n };\n}\n","import * as aws from \"@pulumi/aws\";\n\n/**\n * SQS resources output\n */\nexport type SQSResources = {\n queue: aws.sqs.Queue;\n dlq: aws.sqs.Queue;\n};\n\n/**\n * Create SQS queue with Dead Letter Queue for event processing\n *\n * Architecture:\n * EventBridge -> SQS Queue -> Lambda (event-processor)\n * ↓\n * DLQ (failed messages after 3 retries)\n */\nexport async function createSQSResources(): Promise<SQSResources> {\n // Dead Letter Queue for failed event processing\n const dlq = new aws.sqs.Queue(\"wraps-email-events-dlq\", {\n name: \"wraps-email-events-dlq\",\n messageRetentionSeconds: 1_209_600, // 14 days\n tags: {\n ManagedBy: \"wraps-cli\",\n Description: \"Dead letter queue for failed SES event processing\",\n },\n });\n\n // Main queue for SES events\n const queue = new aws.sqs.Queue(\"wraps-email-events\", {\n name: \"wraps-email-events\",\n visibilityTimeoutSeconds: 300, // 5 minutes (Lambda timeout)\n messageRetentionSeconds: 345_600, // 4 days\n receiveWaitTimeSeconds: 20, // Long polling\n redrivePolicy: dlq.arn.apply((arn) =>\n JSON.stringify({\n deadLetterTargetArn: arn,\n maxReceiveCount: 3, // Retry 3 times before sending to DLQ\n })\n ),\n tags: {\n ManagedBy: \"wraps-cli\",\n Description: \"Queue for SES email events from EventBridge\",\n },\n });\n\n return {\n queue,\n dlq,\n };\n}\n","import * as aws from \"@pulumi/aws\";\n\n/**\n * Vercel OIDC configuration\n */\nexport type VercelOIDCConfig = {\n teamSlug: string;\n accountId: string;\n};\n\n/**\n * Get existing OIDC provider ARN by URL\n */\nasync function getExistingOIDCProviderArn(url: string): Promise<string | null> {\n try {\n const { IAMClient, ListOpenIDConnectProvidersCommand } = await import(\n \"@aws-sdk/client-iam\"\n );\n // IAM is global but SDK still requires a region\n const iam = new IAMClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n\n const response = await iam.send(new ListOpenIDConnectProvidersCommand({}));\n\n // Find provider by ARN pattern (ARN includes the URL)\n // Format: arn:aws:iam::ACCOUNT:oidc-provider/oidc.vercel.com/TEAM\n const expectedArnSuffix = url.replace(\"https://\", \"\");\n const provider = response.OpenIDConnectProviderList?.find((p) =>\n p.Arn?.endsWith(expectedArnSuffix)\n );\n\n return provider?.Arn || null;\n } catch (error) {\n console.error(\"Error checking for existing OIDC provider:\", error);\n return null;\n }\n}\n\n/**\n * Create or get existing Vercel OIDC provider for AssumeRoleWithWebIdentity\n */\nexport async function createVercelOIDC(\n config: VercelOIDCConfig\n): Promise<aws.iam.OpenIdConnectProvider> {\n const url = `https://oidc.vercel.com/${config.teamSlug}`;\n\n // Check if OIDC provider already exists\n const existingArn = await getExistingOIDCProviderArn(url);\n\n if (existingArn) {\n // Import existing OIDC provider instead of creating new one\n return new aws.iam.OpenIdConnectProvider(\n \"wraps-vercel-oidc\",\n {\n url,\n clientIdLists: [`https://vercel.com/${config.teamSlug}`],\n thumbprintLists: [\n // Vercel OIDC thumbprints\n \"20032e77eca0785eece16b56b42c9b330b906320\",\n \"696db3af0dffc17e65c6a20d925c5a7bd24dec7e\",\n ],\n tags: {\n ManagedBy: \"wraps-cli\",\n Provider: \"vercel\",\n },\n },\n {\n import: existingArn, // Import existing resource\n }\n );\n }\n\n // Create new OIDC provider if it doesn't exist\n return new aws.iam.OpenIdConnectProvider(\"wraps-vercel-oidc\", {\n url,\n clientIdLists: [`https://vercel.com/${config.teamSlug}`],\n thumbprintLists: [\n // Vercel OIDC thumbprints\n \"20032e77eca0785eece16b56b42c9b330b906320\",\n \"696db3af0dffc17e65c6a20d925c5a7bd24dec7e\",\n ],\n tags: {\n ManagedBy: \"wraps-cli\",\n Provider: \"vercel\",\n },\n });\n}\n","import { exec } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport * as automation from \"@pulumi/pulumi/automation/index.js\";\nimport { errors } from \"./errors.js\";\n\nconst execAsync = promisify(exec);\n\n// Extract installPulumiCli from the automation module\nconst installPulumiCli = (automation as any).installPulumiCli;\n\n/**\n * Check if Pulumi CLI is installed\n */\nexport async function checkPulumiInstalled(): Promise<boolean> {\n try {\n await execAsync(\"pulumi version\");\n return true;\n } catch (_error) {\n return false;\n }\n}\n\n/**\n * Ensure Pulumi CLI is installed, auto-install if missing\n * @returns true if Pulumi was auto-installed, false if it was already installed\n */\nexport async function ensurePulumiInstalled(): Promise<boolean> {\n const isInstalled = await checkPulumiInstalled();\n\n if (!isInstalled) {\n try {\n // Try to auto-install Pulumi CLI using Automation API\n await installPulumiCli();\n return true; // Was auto-installed\n } catch (_error) {\n // If auto-install fails, throw helpful error\n throw errors.pulumiNotInstalled();\n }\n }\n\n return false; // Was already installed\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { deployEmailStack } from \"../../infrastructure/email-stack.js\";\nimport {\n trackError,\n trackServiceDeployed,\n trackServiceInit,\n} from \"../../telemetry/events.js\";\nimport type { ConnectOptions, EmailStackConfig } from \"../../types/index.js\";\nimport { getPreset } from \"../../utils/email/presets.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { errors } from \"../../utils/shared/errors.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n createConnectionMetadata,\n loadConnectionMetadata,\n saveConnectionMetadata,\n} from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayPreview,\n displaySuccess,\n} from \"../../utils/shared/output.js\";\nimport {\n confirmConnect,\n promptConfigPreset,\n promptProvider,\n promptRegion,\n promptSelectIdentities,\n promptVercelConfig,\n} from \"../../utils/shared/prompts.js\";\nimport { ensurePulumiInstalled } from \"../../utils/shared/pulumi.js\";\nimport { scanAWSResources } from \"../../utils/shared/scanner.js\";\n\n/**\n * Connect command - Connect to existing AWS SES infrastructure\n */\nexport async function connect(options: ConnectOptions): Promise<void> {\n const startTime = Date.now();\n\n clack.intro(\n pc.bold(\n options.preview\n ? \"Wraps Connect Preview\"\n : \"Wraps Connect - Link Existing Infrastructure\"\n )\n );\n\n const progress = new DeploymentProgress();\n\n // 1. Check Pulumi CLI is installed\n const wasAutoInstalled = await progress.execute(\n \"Checking Pulumi CLI installation\",\n async () => await ensurePulumiInstalled()\n );\n\n if (wasAutoInstalled) {\n progress.info(\"Pulumi CLI was automatically installed\");\n }\n\n // 2. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`Connected to AWS account: ${pc.cyan(identity.accountId)}`);\n\n // 3. Get region\n let region = options.region;\n if (!region) {\n const defaultRegion = await getAWSRegion();\n region = await promptRegion(defaultRegion);\n }\n\n // 4. Check if connection already exists\n const existingConnection = await loadConnectionMetadata(\n identity.accountId,\n region\n );\n if (existingConnection) {\n clack.log.warn(\n `Connection already exists for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n clack.log.info(`Created: ${existingConnection.timestamp}`);\n clack.log.info(`Use ${pc.cyan(\"wraps status\")} to view current setup`);\n clack.log.info(`Use ${pc.cyan(\"wraps upgrade\")} to add more features`);\n process.exit(0);\n }\n\n // 5. Scan existing AWS resources\n const scan = await progress.execute(\n \"Scanning existing AWS resources\",\n async () => scanAWSResources(region)\n );\n\n // Display what we found\n progress.info(\n `Found: ${scan.identities.length} identities, ${scan.configurationSets.length} config sets`\n );\n\n // Check if any identities exist\n if (scan.identities.length === 0) {\n clack.log.warn(\"No SES identities found in this region.\");\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} to create new email infrastructure instead.`\n );\n process.exit(0);\n }\n\n // Show verified identities\n const verifiedIdentities = scan.identities.filter((id) => id.verified);\n if (verifiedIdentities.length > 0) {\n progress.info(\n `Verified identities: ${verifiedIdentities.map((id) => pc.cyan(id.name)).join(\", \")}`\n );\n }\n\n // 6. Get provider configuration\n let provider = options.provider;\n if (!provider) {\n provider = await promptProvider();\n }\n\n // Get Vercel config if needed\n let vercelConfig;\n if (provider === \"vercel\") {\n vercelConfig = await promptVercelConfig();\n }\n\n // 7. Select identities to connect\n const selectedIdentities = await promptSelectIdentities(\n scan.identities.map((id) => ({\n name: id.name,\n verified: id.verified,\n }))\n );\n\n if (selectedIdentities.length === 0) {\n clack.log.warn(\"No identities selected. Nothing to connect.\");\n process.exit(0);\n }\n\n // 8. Select configuration preset\n const preset = await promptConfigPreset();\n const emailConfig =\n preset === \"custom\"\n ? await import(\"../../utils/shared/prompts.js\").then((m) =>\n m.promptCustomConfig()\n )\n : getPreset(preset)!;\n\n // 8a. Set the domain from the first selected identity (if it's a domain, not an email)\n // Filter to only domains (exclude email addresses)\n const domainIdentities = selectedIdentities.filter((id) => !id.includes(\"@\"));\n if (domainIdentities.length > 0) {\n emailConfig.domain = domainIdentities[0];\n }\n\n // 9. Confirm deployment (skip if --yes or --preview)\n if (!(options.yes || options.preview)) {\n const confirmed = await confirmConnect();\n if (!confirmed) {\n clack.cancel(\"Connection cancelled.\");\n process.exit(0);\n }\n }\n\n // 10. Build stack configuration\n const stackConfig: EmailStackConfig = {\n provider,\n region,\n vercel: vercelConfig,\n emailConfig,\n };\n\n // 11. Preview or Deploy infrastructure using Pulumi\n if (options.preview) {\n // PREVIEW MODE - show what would be created without deploying\n try {\n const previewResult = await progress.execute(\n \"Generating infrastructure preview\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName: `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Run preview instead of deployment\n const result = await stack.preview({ diff: true });\n return result;\n }\n );\n\n // Display preview results\n displayPreview({\n changeSummary: previewResult.changeSummary,\n commandName: \"wraps email connect\",\n });\n\n clack.outro(\n pc.green(\"Preview complete. Run without --preview to connect.\")\n );\n\n // Track preview completion\n trackServiceInit(\"email\", true, {\n preset,\n provider,\n preview: true,\n duration_ms: Date.now() - startTime,\n existing_identities: selectedIdentities.length,\n });\n return;\n } catch (error: any) {\n trackError(\"PREVIEW_FAILED\", \"email:connect\", { step: \"preview\" });\n if (error.message?.includes(\"stack is currently locked\")) {\n throw errors.stackLocked();\n }\n throw new Error(`Preview failed: ${error.message}`);\n }\n }\n\n // DEPLOY MODE - actually create infrastructure\n let outputs;\n try {\n outputs = await progress.execute(\n \"Deploying Wraps infrastructure (this may take 2-3 minutes)\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName: `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.workspace.selectStack(\n `wraps-${identity.accountId}-${region}`\n );\n await stack.setConfig(\"aws:region\", { value: region });\n\n const upResult = await stack.up({ onOutput: () => {} });\n const pulumiOutputs = upResult.outputs;\n\n return {\n roleArn: pulumiOutputs.roleArn?.value as string,\n configSetName: pulumiOutputs.configSetName?.value as\n | string\n | undefined,\n tableName: pulumiOutputs.tableName?.value as string | undefined,\n region: pulumiOutputs.region?.value as string,\n lambdaFunctions: pulumiOutputs.lambdaFunctions?.value as\n | string[]\n | undefined,\n domain: pulumiOutputs.domain?.value as string | undefined,\n dkimTokens: pulumiOutputs.dkimTokens?.value as string[] | undefined,\n customTrackingDomain: pulumiOutputs.customTrackingDomain?.value as\n | string\n | undefined,\n };\n }\n );\n } catch (error: any) {\n // Track deployment failure\n trackServiceInit(\"email\", false, {\n preset,\n provider,\n duration_ms: Date.now() - startTime,\n });\n\n // Check if it's a lock file error\n if (error.message?.includes(\"stack is currently locked\")) {\n trackError(\"STACK_LOCKED\", \"email:connect\", { step: \"deploy\" });\n throw errors.stackLocked();\n }\n\n trackError(\"DEPLOYMENT_FAILED\", \"email:connect\", { step: \"deploy\" });\n throw new Error(`Pulumi deployment failed: ${error.message}`);\n }\n\n // 12. Create DNS records in Route53 (if hosted zone exists)\n if (outputs.domain && outputs.dkimTokens && outputs.dkimTokens.length > 0) {\n const { findHostedZone, createDNSRecords } = await import(\n \"../../utils/email/route53.js\"\n );\n const hostedZone = await findHostedZone(outputs.domain, region);\n\n if (hostedZone) {\n try {\n progress.start(\"Creating DNS records in Route53\");\n\n // Determine mailFromDomain - use outputs if available, otherwise construct default\n const mailFromDomain =\n emailConfig.mailFromDomain || `mail.${outputs.domain}`;\n\n await createDNSRecords(\n hostedZone.id,\n outputs.domain,\n outputs.dkimTokens,\n region,\n outputs.customTrackingDomain,\n mailFromDomain\n );\n progress.succeed(\"DNS records created in Route53\");\n } catch (error: any) {\n progress.fail(\n `Failed to create DNS records automatically: ${error.message}`\n );\n progress.info(\n \"You can manually add the required DNS records shown below\"\n );\n }\n }\n }\n\n // 13. Save metadata\n const metadata = createConnectionMetadata(\n identity.accountId,\n region,\n provider,\n emailConfig,\n preset === \"custom\" ? undefined : preset\n );\n if (metadata.services.email) {\n metadata.services.email.pulumiStackName = `wraps-${identity.accountId}-${region}`;\n }\n if (vercelConfig) {\n metadata.vercel = vercelConfig;\n }\n await saveConnectionMetadata(metadata);\n\n progress.info(\"Connection metadata saved\");\n\n // 14. Display success message\n displaySuccess({\n roleArn: outputs.roleArn,\n configSetName: outputs.configSetName,\n region: outputs.region!,\n tableName: outputs.tableName,\n });\n\n // Show next steps\n if (selectedIdentities.length > 0 && emailConfig.tracking?.enabled) {\n console.log(`\\n${pc.bold(\"Next Steps:\")}\\n`);\n console.log(\n `Update your code to use configuration set: ${pc.cyan(\"wraps-email-tracking\")}`\n );\n console.log(`\\n${pc.dim(\"Example:\")}`);\n console.log(\n pc.gray(` await ses.sendEmail({\n ConfigurationSetName: 'wraps-email-tracking',\n // ... other parameters\n });`)\n );\n console.log(\"\");\n }\n\n // 15. Track successful connection\n const duration = Date.now() - startTime;\n const enabledFeatures: string[] = [];\n if (emailConfig.tracking?.enabled) enabledFeatures.push(\"tracking\");\n if (emailConfig.suppressionList?.enabled)\n enabledFeatures.push(\"suppression_list\");\n if (emailConfig.eventTracking?.enabled)\n enabledFeatures.push(\"event_tracking\");\n if (emailConfig.eventTracking?.dynamoDBHistory)\n enabledFeatures.push(\"dynamodb_history\");\n\n trackServiceInit(\"email\", true, {\n preset,\n provider,\n features: enabledFeatures,\n duration_ms: duration,\n existing_identities: selectedIdentities.length,\n });\n\n trackServiceDeployed(\"email\", {\n duration_ms: duration,\n features: enabledFeatures,\n preset,\n });\n}\n","import {\n DescribeTableCommand,\n DynamoDBClient,\n ListTablesCommand,\n} from \"@aws-sdk/client-dynamodb\";\nimport { IAMClient, ListRolesCommand } from \"@aws-sdk/client-iam\";\nimport { LambdaClient, ListFunctionsCommand } from \"@aws-sdk/client-lambda\";\nimport {\n DescribeConfigurationSetCommand,\n GetIdentityVerificationAttributesCommand,\n ListConfigurationSetsCommand,\n ListIdentitiesCommand,\n SESClient,\n} from \"@aws-sdk/client-ses\";\nimport {\n GetTopicAttributesCommand,\n ListTopicsCommand,\n SNSClient,\n} from \"@aws-sdk/client-sns\";\n\n/**\n * SES Identity with configuration\n */\nexport type SESIdentity = {\n name: string;\n type: \"Domain\" | \"EmailAddress\";\n verified: boolean;\n configurationSet?: string;\n dkimEnabled?: boolean;\n};\n\n/**\n * SES Configuration Set\n */\nexport type SESConfigurationSet = {\n name: string;\n eventDestinations: Array<{\n name: string;\n enabled: boolean;\n matchingEventTypes: string[];\n snsDestination?: string;\n cloudWatchDestination?: any;\n }>;\n};\n\n/**\n * SNS Topic\n */\nexport type SNSTopic = {\n arn: string;\n name: string;\n subscriptions?: number;\n};\n\n/**\n * DynamoDB Table\n */\nexport type DynamoTable = {\n name: string;\n status: string;\n itemCount?: number;\n sizeBytes?: number;\n};\n\n/**\n * Lambda Function\n */\nexport type LambdaFunction = {\n name: string;\n arn: string;\n runtime?: string;\n handler?: string;\n};\n\n/**\n * IAM Role\n */\nexport type IAMRole = {\n name: string;\n arn: string;\n assumeRolePolicyDocument: string;\n};\n\n/**\n * Complete scan of existing AWS resources\n */\nexport type AWSResourceScan = {\n identities: SESIdentity[];\n configurationSets: SESConfigurationSet[];\n snsTopics: SNSTopic[];\n dynamoTables: DynamoTable[];\n lambdaFunctions: LambdaFunction[];\n iamRoles: IAMRole[];\n};\n\n/**\n * Scan all existing SES identities (domains and email addresses)\n */\nexport async function scanSESIdentities(\n region: string\n): Promise<SESIdentity[]> {\n const ses = new SESClient({ region });\n const identities: SESIdentity[] = [];\n\n try {\n // List all identities\n const listResponse = await ses.send(new ListIdentitiesCommand({}));\n const identityNames = listResponse.Identities || [];\n\n if (identityNames.length === 0) {\n return [];\n }\n\n // Get verification attributes\n const attrsResponse = await ses.send(\n new GetIdentityVerificationAttributesCommand({\n Identities: identityNames,\n })\n );\n\n const attrs = attrsResponse.VerificationAttributes || {};\n\n // Build identity objects\n for (const name of identityNames) {\n const attr = attrs[name];\n identities.push({\n name,\n type: name.includes(\"@\") ? \"EmailAddress\" : \"Domain\",\n verified: attr?.VerificationStatus === \"Success\",\n });\n }\n\n return identities;\n } catch (error: any) {\n console.error(\"Error scanning SES identities:\", error.message);\n return [];\n }\n}\n\n/**\n * Scan all SES configuration sets\n */\nexport async function scanSESConfigurationSets(\n region: string\n): Promise<SESConfigurationSet[]> {\n const ses = new SESClient({ region });\n const configSets: SESConfigurationSet[] = [];\n\n try {\n // List configuration sets\n const listResponse = await ses.send(new ListConfigurationSetsCommand({}));\n const configSetNames =\n listResponse.ConfigurationSets?.map((cs) => cs.Name!).filter(Boolean) ||\n [];\n\n // Get details for each config set\n for (const name of configSetNames) {\n try {\n const describeResponse = await ses.send(\n new DescribeConfigurationSetCommand({ ConfigurationSetName: name })\n );\n\n const eventDestinations =\n describeResponse.EventDestinations?.map((ed) => ({\n name: ed.Name!,\n enabled: ed.Enabled ?? false,\n matchingEventTypes: ed.MatchingEventTypes || [],\n snsDestination: ed.SNSDestination?.TopicARN,\n cloudWatchDestination: ed.CloudWatchDestination,\n })) || [];\n\n configSets.push({\n name,\n eventDestinations,\n });\n } catch (error: any) {\n console.error(`Error describing config set ${name}:`, error.message);\n }\n }\n\n return configSets;\n } catch (error: any) {\n console.error(\"Error scanning SES configuration sets:\", error.message);\n return [];\n }\n}\n\n/**\n * Scan SNS topics (filter for email-related ones)\n */\nexport async function scanSNSTopics(region: string): Promise<SNSTopic[]> {\n const sns = new SNSClient({ region });\n const topics: SNSTopic[] = [];\n\n try {\n // List all topics\n const listResponse = await sns.send(new ListTopicsCommand({}));\n const topicArns =\n listResponse.Topics?.map((t) => t.TopicArn!).filter(Boolean) || [];\n\n // Get details for each topic\n for (const arn of topicArns) {\n try {\n const attrsResponse = await sns.send(\n new GetTopicAttributesCommand({ TopicArn: arn })\n );\n\n const name = arn.split(\":\").pop() || arn;\n const subscriptions = Number.parseInt(\n attrsResponse.Attributes?.SubscriptionsConfirmed || \"0\",\n 10\n );\n\n topics.push({\n arn,\n name,\n subscriptions,\n });\n } catch (error: any) {\n console.error(\n `Error getting topic attributes for ${arn}:`,\n error.message\n );\n }\n }\n\n return topics;\n } catch (error: any) {\n console.error(\"Error scanning SNS topics:\", error.message);\n return [];\n }\n}\n\n/**\n * Scan DynamoDB tables (filter for email-related ones)\n */\nexport async function scanDynamoTables(region: string): Promise<DynamoTable[]> {\n const dynamo = new DynamoDBClient({ region });\n const tables: DynamoTable[] = [];\n\n try {\n // List all tables\n const listResponse = await dynamo.send(new ListTablesCommand({}));\n const tableNames = listResponse.TableNames || [];\n\n // Get details for each table\n for (const name of tableNames) {\n try {\n const describeResponse = await dynamo.send(\n new DescribeTableCommand({ TableName: name })\n );\n\n const table = describeResponse.Table;\n if (table) {\n tables.push({\n name,\n status: table.TableStatus || \"UNKNOWN\",\n itemCount: table.ItemCount,\n sizeBytes: table.TableSizeBytes,\n });\n }\n } catch (error: any) {\n console.error(`Error describing table ${name}:`, error.message);\n }\n }\n\n return tables;\n } catch (error: any) {\n console.error(\"Error scanning DynamoDB tables:\", error.message);\n return [];\n }\n}\n\n/**\n * Scan Lambda functions (filter for email-related ones)\n */\nexport async function scanLambdaFunctions(\n region: string\n): Promise<LambdaFunction[]> {\n const lambda = new LambdaClient({ region });\n const functions: LambdaFunction[] = [];\n\n try {\n // List all functions\n const listResponse = await lambda.send(new ListFunctionsCommand({}));\n const functionConfigs = listResponse.Functions || [];\n\n for (const func of functionConfigs) {\n if (func.FunctionName && func.FunctionArn) {\n functions.push({\n name: func.FunctionName,\n arn: func.FunctionArn,\n runtime: func.Runtime,\n handler: func.Handler,\n });\n }\n }\n\n return functions;\n } catch (error: any) {\n console.error(\"Error scanning Lambda functions:\", error.message);\n return [];\n }\n}\n\n/**\n * Scan IAM roles (filter for Wraps or email-related ones)\n */\nexport async function scanIAMRoles(region: string): Promise<IAMRole[]> {\n const iam = new IAMClient({ region });\n const roles: IAMRole[] = [];\n\n try {\n // List all roles (with pagination support)\n let marker: string | undefined;\n let hasMore = true;\n\n while (hasMore) {\n const listResponse = await iam.send(\n new ListRolesCommand({\n Marker: marker,\n MaxItems: 100,\n })\n );\n\n const roleList = listResponse.Roles || [];\n\n for (const role of roleList) {\n if (role.RoleName && role.Arn) {\n roles.push({\n name: role.RoleName,\n arn: role.Arn,\n assumeRolePolicyDocument: role.AssumeRolePolicyDocument || \"\",\n });\n }\n }\n\n marker = listResponse.Marker;\n hasMore = listResponse.IsTruncated ?? false;\n }\n\n return roles;\n } catch (error: any) {\n console.error(\"Error scanning IAM roles:\", error.message);\n return [];\n }\n}\n\n/**\n * Scan all relevant AWS resources for email infrastructure\n */\nexport async function scanAWSResources(\n region: string\n): Promise<AWSResourceScan> {\n const [\n identities,\n configurationSets,\n snsTopics,\n dynamoTables,\n lambdaFunctions,\n iamRoles,\n ] = await Promise.all([\n scanSESIdentities(region),\n scanSESConfigurationSets(region),\n scanSNSTopics(region),\n scanDynamoTables(region),\n scanLambdaFunctions(region),\n scanIAMRoles(region),\n ]);\n\n return {\n identities,\n configurationSets,\n snsTopics,\n dynamoTables,\n lambdaFunctions,\n iamRoles,\n };\n}\n\n/**\n * Filter resources to only Wraps-managed ones (wraps-* prefix)\n */\nexport function filterWrapsResources(scan: AWSResourceScan): AWSResourceScan {\n return {\n identities: scan.identities, // All identities are relevant\n configurationSets: scan.configurationSets.filter((cs) =>\n cs.name.startsWith(\"wraps-\")\n ),\n snsTopics: scan.snsTopics.filter((t) => t.name.startsWith(\"wraps-\")),\n dynamoTables: scan.dynamoTables.filter((t) => t.name.startsWith(\"wraps-\")),\n lambdaFunctions: scan.lambdaFunctions.filter((f) =>\n f.name.startsWith(\"wraps-\")\n ),\n iamRoles: scan.iamRoles.filter((r) => r.name.startsWith(\"wraps-\")),\n };\n}\n\n/**\n * Check if specific Wraps resources exist\n */\nexport function checkWrapsResourcesExist(scan: AWSResourceScan): {\n hasConfigSet: boolean;\n hasSNSTopics: boolean;\n hasDynamoTable: boolean;\n hasLambdaFunctions: boolean;\n hasIAMRole: boolean;\n} {\n const filtered = filterWrapsResources(scan);\n\n return {\n hasConfigSet: filtered.configurationSets.length > 0,\n hasSNSTopics: filtered.snsTopics.length > 0,\n hasDynamoTable: filtered.dynamoTables.length > 0,\n hasLambdaFunctions: filtered.lambdaFunctions.length > 0,\n hasIAMRole: filtered.iamRoles.length > 0,\n };\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport {\n trackError,\n trackServiceRemoved,\n} from \"../../telemetry/events.js\";\nimport type { DestroyOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n deleteConnectionMetadata,\n loadConnectionMetadata,\n} from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayPreview,\n} from \"../../utils/shared/output.js\";\nimport { deleteDNSRecords, findHostedZone } from \"../../utils/route53.js\";\n\n/**\n * Get DKIM tokens for a domain from SES\n */\nasync function getDkimTokensFromSES(\n domain: string,\n region: string\n): Promise<string[]> {\n try {\n const { SESv2Client, GetEmailIdentityCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n const ses = new SESv2Client({ region });\n\n const response = await ses.send(\n new GetEmailIdentityCommand({ EmailIdentity: domain })\n );\n\n return response.DkimAttributes?.Tokens || [];\n } catch (_error) {\n return [];\n }\n}\n\n/**\n * Email Destroy command - Remove email infrastructure\n */\nexport async function emailDestroy(options: DestroyOptions): Promise<void> {\n const startTime = Date.now();\n\n clack.intro(\n pc.bold(\n options.preview\n ? \"Email Infrastructure Destruction Preview\"\n : \"Email Infrastructure Teardown\"\n )\n );\n\n const progress = new DeploymentProgress();\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region\n const region = await getAWSRegion();\n\n // 3. Load connection metadata to get domain info and stack name\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n const emailService = metadata?.services?.email;\n const emailConfig = emailService?.config;\n const domain = emailConfig?.domain;\n const storedStackName = emailService?.pulumiStackName;\n\n // 4. Confirm destruction (skip if --force or --preview)\n if (!(options.force || options.preview)) {\n const confirmed = await clack.confirm({\n message: pc.red(\n \"Are you sure you want to destroy all email infrastructure?\"\n ),\n initialValue: false,\n });\n\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel(\"Destruction cancelled.\");\n process.exit(0);\n }\n }\n\n // 5. Check for Route53 hosted zone and offer to clean up DNS\n let shouldCleanDNS = false;\n let hostedZone: { id: string; name: string } | null = null;\n let dkimTokens: string[] = [];\n\n if (domain && !options.preview) {\n hostedZone = await findHostedZone(domain, region);\n\n if (hostedZone) {\n // Get DKIM tokens from SES before we destroy\n dkimTokens = await getDkimTokensFromSES(domain, region);\n\n if (!options.force) {\n const cleanDNS = await clack.confirm({\n message: `Found Route53 hosted zone for ${pc.cyan(domain)}. Delete DNS records (DKIM, DMARC, MAIL FROM)?`,\n initialValue: true,\n });\n\n if (clack.isCancel(cleanDNS)) {\n clack.cancel(\"Destruction cancelled.\");\n process.exit(0);\n }\n\n shouldCleanDNS = cleanDNS;\n } else {\n shouldCleanDNS = true; // Auto-clean with --force\n }\n }\n }\n\n // 6. Preview or Destroy infrastructure using Pulumi\n if (options.preview) {\n // PREVIEW MODE - show what would be destroyed without actually destroying\n try {\n const previewResult = await progress.execute(\n \"Generating destruction preview\",\n async () => {\n await ensurePulumiWorkDir();\n\n // Use stored stack name from metadata, fallback to generated name\n const stackName =\n storedStackName || `wraps-email-${identity.accountId}-${region}`;\n\n // Try to select the stack\n let stack;\n try {\n stack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName,\n workDir: getPulumiWorkDir(),\n });\n } catch (_error) {\n throw new Error(\"No email infrastructure found to preview\");\n }\n\n // Run preview to see what would be destroyed\n const result = await stack.preview({ diff: true });\n return result;\n }\n );\n\n // Display preview results\n displayPreview({\n changeSummary: previewResult.changeSummary,\n costEstimate: \"Monthly cost after destruction: $0.00\",\n commandName: \"wraps email destroy\",\n });\n\n // Show DNS cleanup info\n if (domain) {\n const previewHostedZone = await findHostedZone(domain, region);\n if (previewHostedZone) {\n clack.log.info(\n `DNS records in Route53 for ${pc.cyan(domain)} will also be deleted`\n );\n }\n }\n\n clack.outro(\n pc.green(\"Preview complete. Run without --preview to destroy.\")\n );\n\n // Track preview completion\n trackServiceRemoved(\"email\", {\n preview: true,\n duration_ms: Date.now() - startTime,\n });\n return;\n } catch (error: any) {\n progress.stop();\n if (error.message.includes(\"No email infrastructure found\")) {\n clack.log.warn(\"No email infrastructure found to preview\");\n process.exit(0);\n }\n trackError(\"PREVIEW_FAILED\", \"email destroy\", { step: \"preview\" });\n throw new Error(`Preview failed: ${error.message}`);\n }\n }\n\n // DESTROY MODE - actually remove infrastructure\n\n // 7. Clean up DNS records first (before destroying SES identity)\n if (shouldCleanDNS && hostedZone && domain && dkimTokens.length > 0) {\n try {\n await progress.execute(\n `Deleting DNS records for ${domain}`,\n async () => {\n await deleteDNSRecords(\n hostedZone.id,\n domain,\n dkimTokens,\n region,\n emailConfig?.tracking?.customRedirectDomain,\n emailConfig?.mailFromDomain\n );\n }\n );\n } catch (error: any) {\n clack.log.warn(`Could not delete DNS records: ${error.message}`);\n clack.log.info(\"You may need to delete them manually from Route53\");\n }\n }\n\n // 8. Destroy Pulumi infrastructure\n try {\n await progress.execute(\n \"Destroying email infrastructure (this may take 2-3 minutes)\",\n async () => {\n // Ensure Pulumi workspace directory exists\n await ensurePulumiWorkDir();\n\n // Use stored stack name from metadata, fallback to generated name\n const stackName =\n storedStackName || `wraps-email-${identity.accountId}-${region}`;\n\n // Try to select the stack\n let stack;\n try {\n stack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName,\n workDir: getPulumiWorkDir(),\n });\n } catch (_error) {\n throw new Error(\"No email infrastructure found to destroy\");\n }\n\n // Run destroy\n await stack.destroy({ onOutput: () => {} }); // Suppress Pulumi output\n\n // Remove the stack from workspace\n await stack.workspace.removeStack(stackName);\n }\n );\n } catch (error: any) {\n progress.stop();\n if (error.message.includes(\"No email infrastructure found\")) {\n clack.log.warn(\"No email infrastructure found\");\n // Still delete metadata if it exists\n await deleteConnectionMetadata(identity.accountId, region);\n process.exit(0);\n }\n trackError(\"DESTROY_FAILED\", \"email destroy\", { step: \"destroy\" });\n clack.log.error(\"Email infrastructure destruction failed\");\n throw error;\n }\n\n // 9. Delete connection metadata\n await deleteConnectionMetadata(identity.accountId, region);\n\n // 10. Display success message\n progress.stop();\n\n const deletedItems = [\"AWS infrastructure\"];\n if (shouldCleanDNS && hostedZone) {\n deletedItems.push(\"Route53 DNS records\");\n }\n\n clack.outro(pc.green(`Email infrastructure has been removed`));\n\n if (domain) {\n console.log(`\\n${pc.bold(\"Cleaned up:\")}`);\n for (const item of deletedItems) {\n console.log(` ${pc.green(\"✓\")} ${item}`);\n }\n\n // Remind about SPF record\n console.log(\n `\\n${pc.dim(\"Note: SPF record was not deleted. Remove 'include:amazonses.com' manually if needed.\")}`\n );\n }\n\n console.log(\n `\\nRun ${pc.cyan(\"wraps email init\")} to deploy infrastructure again.\\n`\n );\n\n // 11. Track successful destruction\n trackServiceRemoved(\"email\", {\n reason: \"user_initiated\",\n duration_ms: Date.now() - startTime,\n dns_cleaned: shouldCleanDNS,\n });\n}\n","import {\n type Change,\n ChangeResourceRecordSetsCommand,\n ListHostedZonesByNameCommand,\n ListResourceRecordSetsCommand,\n Route53Client,\n} from \"@aws-sdk/client-route-53\";\n\n/**\n * Get existing TXT records for a domain\n * Returns all TXT record values and identifies which one is SPF\n */\nasync function getExistingTXTRecords(\n client: Route53Client,\n hostedZoneId: string,\n domain: string\n): Promise<{ allValues: string[]; spfValue: string | null; ttl: number }> {\n try {\n const response = await client.send(\n new ListResourceRecordSetsCommand({\n HostedZoneId: hostedZoneId,\n StartRecordName: domain,\n StartRecordType: \"TXT\",\n MaxItems: 100,\n })\n );\n\n // Find TXT records for the exact domain\n const txtRecordSet = response.ResourceRecordSets?.find(\n (rs) =>\n rs.Type === \"TXT\" &&\n (rs.Name === domain || rs.Name === `${domain}.`)\n );\n\n if (!txtRecordSet || !txtRecordSet.ResourceRecords) {\n return { allValues: [], spfValue: null, ttl: 1800 };\n }\n\n const allValues: string[] = [];\n let spfValue: string | null = null;\n\n for (const record of txtRecordSet.ResourceRecords) {\n const value = record.Value || \"\";\n allValues.push(value);\n\n // Check if this is the SPF record (strip quotes for comparison)\n const unquoted = value.replace(/^\"|\"$/g, \"\");\n if (unquoted.startsWith(\"v=spf1\")) {\n spfValue = unquoted;\n }\n }\n\n return {\n allValues,\n spfValue,\n ttl: txtRecordSet.TTL || 1800,\n };\n } catch (_error) {\n return { allValues: [], spfValue: null, ttl: 1800 };\n }\n}\n\n/**\n * Merge amazonses.com include into an existing SPF record\n * If the record already includes amazonses.com, returns unchanged\n */\nfunction mergeSPFRecord(existingSPF: string): string {\n const sesInclude = \"include:amazonses.com\";\n\n // Already includes SES\n if (existingSPF.includes(sesInclude)) {\n return existingSPF;\n }\n\n // Find the position before the \"all\" mechanism to insert our include\n // SPF format: v=spf1 [mechanisms...] [qualifier]all\n const allMatch = existingSPF.match(/\\s([~+?-]?all)$/);\n\n if (allMatch) {\n // Insert before the \"all\" mechanism\n const beforeAll = existingSPF.slice(0, allMatch.index);\n const allPart = allMatch[1];\n return `${beforeAll} ${sesInclude} ${allPart}`;\n }\n\n // No \"all\" mechanism found, append to end\n return `${existingSPF} ${sesInclude}`;\n}\n\n/**\n * Find Route53 hosted zone for a domain\n */\nexport async function findHostedZone(\n domain: string,\n region: string\n): Promise<{ id: string; name: string } | null> {\n const client = new Route53Client({ region });\n\n try {\n const response = await client.send(\n new ListHostedZonesByNameCommand({\n DNSName: domain,\n MaxItems: 1,\n })\n );\n\n const zone = response.HostedZones?.[0];\n if (zone && zone.Name === `${domain}.` && zone.Id) {\n return {\n id: zone.Id.replace(\"/hostedzone/\", \"\"),\n name: zone.Name,\n };\n }\n\n return null;\n } catch (_error) {\n return null;\n }\n}\n\n/**\n * Create DNS records in Route53\n */\nexport async function createDNSRecords(\n hostedZoneId: string,\n domain: string,\n dkimTokens: string[],\n region: string,\n customTrackingDomain?: string,\n mailFromDomain?: string\n): Promise<void> {\n const client = new Route53Client({ region });\n\n const changes: Change[] = [];\n\n // DKIM CNAME records\n for (const token of dkimTokens) {\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: `${token}._domainkey.${domain}`,\n Type: \"CNAME\",\n TTL: 1800,\n ResourceRecords: [{ Value: `${token}.dkim.amazonses.com` }],\n },\n });\n }\n\n // SPF TXT record - check for existing records and merge while preserving others\n const existingTXT = await getExistingTXTRecords(client, hostedZoneId, domain);\n\n // Build the new TXT record values, preserving all non-SPF records\n const newTXTValues: string[] = [];\n\n if (existingTXT.spfValue) {\n // Merge our include into the existing SPF record\n const mergedSPF = mergeSPFRecord(existingTXT.spfValue);\n newTXTValues.push(`\"${mergedSPF}\"`);\n\n // Add all other TXT values (non-SPF)\n for (const value of existingTXT.allValues) {\n const unquoted = value.replace(/^\"|\"$/g, \"\");\n if (!unquoted.startsWith(\"v=spf1\")) {\n newTXTValues.push(value);\n }\n }\n } else if (existingTXT.allValues.length > 0) {\n // No SPF exists, add new SPF and keep all existing values\n newTXTValues.push('\"v=spf1 include:amazonses.com ~all\"');\n newTXTValues.push(...existingTXT.allValues);\n } else {\n // No TXT records exist, create new SPF\n newTXTValues.push('\"v=spf1 include:amazonses.com ~all\"');\n }\n\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: domain,\n Type: \"TXT\",\n TTL: existingTXT.ttl,\n ResourceRecords: newTXTValues.map((v) => ({ Value: v })),\n },\n });\n\n // DMARC TXT record\n // Use MAIL FROM domain for rua if configured, otherwise use main domain\n const dmarcRuaDomain = mailFromDomain || domain;\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: `_dmarc.${domain}`,\n Type: \"TXT\",\n TTL: 1800,\n ResourceRecords: [\n { Value: `\"v=DMARC1; p=quarantine; rua=mailto:postmaster@${dmarcRuaDomain}\"` },\n ],\n },\n });\n\n // Custom tracking domain CNAME (if provided)\n // This allows SES to rewrite links for open/click tracking using your custom domain\n if (customTrackingDomain) {\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: customTrackingDomain,\n Type: \"CNAME\",\n TTL: 1800,\n ResourceRecords: [{ Value: `r.${region}.awstrack.me` }],\n },\n });\n }\n\n // MAIL FROM domain records (if provided)\n // These records enable DMARC alignment by using a custom subdomain for the envelope sender\n if (mailFromDomain) {\n // MX record pointing to SES feedback server\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: mailFromDomain,\n Type: \"MX\",\n TTL: 1800,\n ResourceRecords: [\n { Value: `10 feedback-smtp.${region}.amazonses.com` },\n ],\n },\n });\n\n // SPF record for MAIL FROM domain\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: mailFromDomain,\n Type: \"TXT\",\n TTL: 1800,\n ResourceRecords: [{ Value: '\"v=spf1 include:amazonses.com ~all\"' }],\n },\n });\n }\n\n await client.send(\n new ChangeResourceRecordSetsCommand({\n HostedZoneId: hostedZoneId,\n ChangeBatch: {\n Changes: changes,\n },\n })\n );\n}\n\n/**\n * Delete DNS records from Route53 that were created for SES\n */\nexport async function deleteDNSRecords(\n hostedZoneId: string,\n domain: string,\n dkimTokens: string[],\n region: string,\n customTrackingDomain?: string,\n mailFromDomain?: string\n): Promise<void> {\n const client = new Route53Client({ region });\n\n // First, we need to get the current record values to delete them\n // Route53 DELETE requires exact match of the record\n const response = await client.send(\n new ListResourceRecordSetsCommand({\n HostedZoneId: hostedZoneId,\n MaxItems: 500,\n })\n );\n\n const recordSets = response.ResourceRecordSets || [];\n const changes: Change[] = [];\n\n // Helper to find and add deletion for a record\n const addDeletionIfExists = (name: string, type: string) => {\n // Route53 names end with a dot\n const normalizedName = name.endsWith(\".\") ? name : `${name}.`;\n const record = recordSets.find(\n (rs) => rs.Name === normalizedName && rs.Type === type\n );\n if (record && record.ResourceRecords) {\n changes.push({\n Action: \"DELETE\",\n ResourceRecordSet: record,\n });\n }\n };\n\n // DKIM CNAME records\n for (const token of dkimTokens) {\n addDeletionIfExists(`${token}._domainkey.${domain}`, \"CNAME\");\n }\n\n // DMARC record\n addDeletionIfExists(`_dmarc.${domain}`, \"TXT\");\n\n // Custom tracking domain CNAME\n if (customTrackingDomain) {\n addDeletionIfExists(customTrackingDomain, \"CNAME\");\n }\n\n // MAIL FROM domain records\n if (mailFromDomain) {\n addDeletionIfExists(mailFromDomain, \"MX\");\n addDeletionIfExists(mailFromDomain, \"TXT\");\n }\n\n // Note: We don't delete the main domain SPF record as it might contain\n // other providers' includes. Users should manually remove amazonses.com\n // from their SPF if needed.\n\n if (changes.length === 0) {\n return; // Nothing to delete\n }\n\n await client.send(\n new ChangeResourceRecordSetsCommand({\n HostedZoneId: hostedZoneId,\n ChangeBatch: {\n Changes: changes,\n },\n })\n );\n}\n","import { Resolver } from \"node:dns/promises\";\nimport { GetEmailIdentityCommand, SESv2Client } from \"@aws-sdk/client-sesv2\";\nimport * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { trackCommand, trackFeature } from \"../../telemetry/events.js\";\nimport type { EmailVerifyOptions } from \"../../types/index.js\";\nimport { getAWSRegion } from \"../../utils/shared/aws.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\n\n/**\n * Verify domain DNS records and verification status\n */\nexport async function verifyDomain(options: EmailVerifyOptions): Promise<void> {\n clack.intro(pc.bold(`Verifying ${options.domain}`));\n\n const progress = new DeploymentProgress();\n const region = await getAWSRegion();\n\n // 1. Check SES verification status\n const sesClient = new SESv2Client({ region });\n let identity;\n let dkimTokens: string[] = [];\n let mailFromDomain: string | undefined;\n\n try {\n identity = await progress.execute(\n \"Checking SES verification status\",\n async () => {\n const response = await sesClient.send(\n new GetEmailIdentityCommand({ EmailIdentity: options.domain })\n );\n return response;\n }\n );\n\n dkimTokens = identity.DkimAttributes?.Tokens || [];\n mailFromDomain = identity.MailFromAttributes?.MailFromDomain;\n } catch (_error: any) {\n progress.stop();\n clack.log.error(`Domain ${options.domain} not found in SES`);\n console.log(\n `\\nRun ${pc.cyan(`wraps email init --domain ${options.domain}`)} to add this domain.\\n`\n );\n process.exit(1);\n return; // Return after process.exit for testing\n }\n\n // 2. Check DNS records\n const resolver = new Resolver();\n // Use public DNS servers for more reliable results\n resolver.setServers([\"8.8.8.8\", \"1.1.1.1\"]);\n const dnsResults: Array<{\n name: string;\n type: string;\n status: string;\n records?: string[];\n }> = [];\n\n // Check DKIM records\n for (const token of dkimTokens) {\n const dkimRecord = `${token}._domainkey.${options.domain}`;\n try {\n const records = await resolver.resolveCname(dkimRecord);\n const expected = `${token}.dkim.amazonses.com`;\n const found = records.some((r) => r === expected || r === `${expected}.`);\n dnsResults.push({\n name: dkimRecord,\n type: \"CNAME\",\n status: found ? \"verified\" : \"incorrect\",\n records,\n });\n } catch (_error) {\n dnsResults.push({\n name: dkimRecord,\n type: \"CNAME\",\n status: \"missing\",\n });\n }\n }\n\n // Check SPF record\n try {\n const records = await resolver.resolveTxt(options.domain);\n const spfRecord = records.flat().find((r) => r.startsWith(\"v=spf1\"));\n const hasAmazonSES = spfRecord?.includes(\"include:amazonses.com\");\n dnsResults.push({\n name: options.domain,\n type: \"TXT (SPF)\",\n status: hasAmazonSES ? \"verified\" : spfRecord ? \"incorrect\" : \"missing\",\n records: spfRecord ? [spfRecord] : undefined,\n });\n } catch (_error) {\n dnsResults.push({\n name: options.domain,\n type: \"TXT (SPF)\",\n status: \"missing\",\n });\n }\n\n // Check DMARC record\n try {\n const records = await resolver.resolveTxt(`_dmarc.${options.domain}`);\n const dmarcRecord = records.flat().find((r) => r.startsWith(\"v=DMARC1\"));\n dnsResults.push({\n name: `_dmarc.${options.domain}`,\n type: \"TXT (DMARC)\",\n status: dmarcRecord ? \"verified\" : \"missing\",\n records: dmarcRecord ? [dmarcRecord] : undefined,\n });\n } catch (_error) {\n dnsResults.push({\n name: `_dmarc.${options.domain}`,\n type: \"TXT (DMARC)\",\n status: \"missing\",\n });\n }\n\n // Check MAIL FROM domain records (if configured)\n if (mailFromDomain) {\n // Check MX record for MAIL FROM domain\n try {\n const mxRecords = await resolver.resolveMx(mailFromDomain);\n const expectedMx = `feedback-smtp.${region}.amazonses.com`;\n const hasMx = mxRecords.some(\n (r) => r.exchange === expectedMx || r.exchange === `${expectedMx}.`\n );\n dnsResults.push({\n name: mailFromDomain,\n type: \"MX\",\n status: hasMx\n ? \"verified\"\n : mxRecords.length > 0\n ? \"incorrect\"\n : \"missing\",\n records: mxRecords.map((r) => `${r.priority} ${r.exchange}`),\n });\n } catch (_error) {\n dnsResults.push({\n name: mailFromDomain,\n type: \"MX\",\n status: \"missing\",\n });\n }\n\n // Check SPF record for MAIL FROM domain\n try {\n const records = await resolver.resolveTxt(mailFromDomain);\n const spfRecord = records.flat().find((r) => r.startsWith(\"v=spf1\"));\n const hasAmazonSES = spfRecord?.includes(\"include:amazonses.com\");\n dnsResults.push({\n name: mailFromDomain,\n type: \"TXT (SPF)\",\n status: hasAmazonSES ? \"verified\" : spfRecord ? \"incorrect\" : \"missing\",\n records: spfRecord ? [spfRecord] : undefined,\n });\n } catch (_error) {\n dnsResults.push({\n name: mailFromDomain,\n type: \"TXT (SPF)\",\n status: \"missing\",\n });\n }\n }\n\n progress.stop();\n\n // 3. Display results\n const verificationStatus = identity.VerifiedForSendingStatus\n ? \"verified\"\n : \"pending\";\n const dkimStatus = identity.DkimAttributes?.Status || \"PENDING\";\n const mailFromStatus =\n identity.MailFromAttributes?.MailFromDomainStatus || \"NOT_CONFIGURED\";\n\n const statusLines = [\n `${pc.bold(\"Domain:\")} ${options.domain}`,\n `${pc.bold(\"Verification Status:\")} ${\n verificationStatus === \"verified\"\n ? pc.green(\"✓ Verified\")\n : pc.yellow(\"⏱ Pending\")\n }`,\n `${pc.bold(\"DKIM Status:\")} ${\n dkimStatus === \"SUCCESS\"\n ? pc.green(\"✓ Success\")\n : pc.yellow(`⏱ ${dkimStatus}`)\n }`,\n ];\n\n if (mailFromDomain) {\n statusLines.push(\n `${pc.bold(\"MAIL FROM Domain:\")} ${mailFromDomain}`,\n `${pc.bold(\"MAIL FROM Status:\")} ${\n mailFromStatus === \"SUCCESS\"\n ? pc.green(\"✓ Success\")\n : mailFromStatus === \"NOT_CONFIGURED\"\n ? pc.yellow(\"⏱ Not Configured\")\n : pc.yellow(`⏱ ${mailFromStatus}`)\n }`\n );\n }\n\n clack.note(statusLines.join(\"\\n\"), \"SES Status\");\n\n // DNS Records\n const dnsLines = dnsResults.map((record) => {\n let statusIcon: string;\n let statusColor: (s: string) => string;\n\n if (record.status === \"verified\") {\n statusIcon = \"✓\";\n statusColor = pc.green;\n } else if (record.status === \"incorrect\") {\n statusIcon = \"✗\";\n statusColor = pc.red;\n } else {\n statusIcon = \"✗\";\n statusColor = pc.red;\n }\n\n const recordInfo = record.records ? ` → ${record.records.join(\", \")}` : \"\";\n return ` ${statusColor(statusIcon)} ${record.name} (${record.type}) ${statusColor(\n record.status\n )}${recordInfo}`;\n });\n\n clack.note(dnsLines.join(\"\\n\"), \"DNS Records\");\n\n // Summary\n const allVerified = dnsResults.every((r) => r.status === \"verified\");\n const someIncorrect = dnsResults.some((r) => r.status === \"incorrect\");\n\n if (verificationStatus === \"verified\" && allVerified) {\n clack.outro(\n pc.green(\"✓ Domain is fully verified and ready to send emails!\")\n );\n trackFeature(\"domain_verified\", { dns_auto_detected: true });\n } else if (someIncorrect) {\n clack.outro(\n pc.red(\"✗ Some DNS records are incorrect. Please update them.\")\n );\n console.log(\n `\\nRun ${pc.cyan(\"wraps email status\")} to see the correct DNS records.\\n`\n );\n } else {\n clack.outro(\n pc.yellow(\"⏱ Waiting for DNS propagation and SES verification\")\n );\n console.log(\"\\nDNS records can take up to 48 hours to propagate.\");\n console.log(\n \"SES verification usually completes within 72 hours after DNS propagation.\\n\"\n );\n }\n\n // Track verify command\n trackCommand(\"email:domains:verify\", {\n success: true,\n verified: verificationStatus === \"verified\" && allVerified,\n dkim_status: dkimStatus,\n });\n}\n\n/**\n * Add a domain to SES for email sending\n */\nexport async function addDomain(options: { domain: string }): Promise<void> {\n clack.intro(pc.bold(`Adding domain ${options.domain} to SES`));\n\n const progress = new DeploymentProgress();\n const region = await getAWSRegion();\n const sesClient = new SESv2Client({ region });\n\n try {\n // Check if domain already exists\n try {\n await sesClient.send(\n new GetEmailIdentityCommand({ EmailIdentity: options.domain })\n );\n progress.stop();\n clack.log.warn(`Domain ${options.domain} already exists in SES`);\n console.log(\n `\\nRun ${pc.cyan(`wraps email domains verify --domain ${options.domain}`)} to check verification status.\\n`\n );\n return;\n } catch (error: any) {\n // Domain doesn't exist, continue with creation\n if (error.name !== \"NotFoundException\") {\n throw error;\n }\n }\n\n // Create the email identity\n const { CreateEmailIdentityCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n await progress.execute(\"Adding domain to SES\", async () => {\n await sesClient.send(\n new CreateEmailIdentityCommand({\n EmailIdentity: options.domain,\n DkimSigningAttributes: {\n NextSigningKeyLength: \"RSA_2048_BIT\",\n },\n })\n );\n });\n\n // Get the DKIM tokens\n const identity = await sesClient.send(\n new GetEmailIdentityCommand({ EmailIdentity: options.domain })\n );\n const dkimTokens = identity.DkimAttributes?.Tokens || [];\n\n progress.stop();\n\n clack.outro(pc.green(`✓ Domain ${options.domain} added successfully!`));\n\n // Show next steps\n console.log(`\\n${pc.bold(\"Next steps:\")}\\n`);\n console.log(\"1. Add the following DKIM records to your DNS:\\n\");\n\n for (const token of dkimTokens) {\n console.log(` ${pc.cyan(`${token}._domainkey.${options.domain}`)}`);\n console.log(\n ` ${pc.dim(\"Type:\")} CNAME ${pc.dim(\"Value:\")} ${token}.dkim.amazonses.com\\n`\n );\n }\n\n console.log(\n `2. Verify DNS propagation: ${pc.cyan(`wraps email domains verify --domain ${options.domain}`)}`\n );\n console.log(`3. Check status: ${pc.cyan(\"wraps email status\")}\\n`);\n\n // Track add domain success\n trackCommand(\"email:domains:add\", {\n success: true,\n });\n trackFeature(\"domain_added\", {});\n } catch (error: any) {\n progress.stop();\n trackCommand(\"email:domains:add\", {\n success: false,\n });\n throw error;\n }\n}\n\n/**\n * List all domains configured in SES\n */\nexport async function listDomains(): Promise<void> {\n clack.intro(pc.bold(\"SES Email Domains\"));\n\n const progress = new DeploymentProgress();\n const region = await getAWSRegion();\n const sesClient = new SESv2Client({ region });\n\n try {\n const { ListEmailIdentitiesCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n\n const identities = await progress.execute(\n \"Loading domains from SES\",\n async () => {\n const response = await sesClient.send(\n new ListEmailIdentitiesCommand({})\n );\n return response.EmailIdentities || [];\n }\n );\n\n // Filter to only domains (not email addresses)\n const domains = identities.filter(\n (identity) =>\n identity.IdentityType === \"DOMAIN\" ||\n (identity.IdentityName && !identity.IdentityName.includes(\"@\"))\n );\n\n progress.stop();\n\n if (domains.length === 0) {\n clack.outro(\"No domains found in SES\");\n console.log(\n `\\nRun ${pc.cyan(\"wraps email domains add <domain>\")} to add a domain.\\n`\n );\n return;\n }\n\n // Get detailed info for each domain\n const domainDetails = await Promise.all(\n domains.map(async (domain) => {\n try {\n const details = await sesClient.send(\n new GetEmailIdentityCommand({\n EmailIdentity: domain.IdentityName!,\n })\n );\n return {\n name: domain.IdentityName!,\n verified: details.VerifiedForSendingStatus,\n dkimStatus: details.DkimAttributes?.Status || \"PENDING\",\n };\n } catch {\n return {\n name: domain.IdentityName!,\n verified: false,\n dkimStatus: \"UNKNOWN\",\n };\n }\n })\n );\n\n // Display domains in a formatted table\n const domainLines = domainDetails.map((domain) => {\n const statusIcon = domain.verified ? pc.green(\"✓\") : pc.yellow(\"⏱\");\n const dkimIcon =\n domain.dkimStatus === \"SUCCESS\" ? pc.green(\"✓\") : pc.yellow(\"⏱\");\n return ` ${statusIcon} ${pc.bold(domain.name)} DKIM: ${dkimIcon} ${domain.dkimStatus}`;\n });\n\n clack.note(\n domainLines.join(\"\\n\"),\n `${domains.length} domain(s) in ${region}`\n );\n clack.outro(\n pc.dim(\n `Run ${pc.cyan(\"wraps email domains verify --domain <domain>\")} for details`\n )\n );\n\n // Track list domains success\n trackCommand(\"email:domains:list\", {\n success: true,\n domain_count: domains.length,\n });\n } catch (error: any) {\n progress.stop();\n trackCommand(\"email:domains:list\", { success: false });\n throw error;\n }\n}\n\n/**\n * Get DKIM tokens for a domain\n */\nexport async function getDkim(options: { domain: string }): Promise<void> {\n clack.intro(pc.bold(`DKIM Tokens for ${options.domain}`));\n\n const progress = new DeploymentProgress();\n const region = await getAWSRegion();\n const sesClient = new SESv2Client({ region });\n\n try {\n const identity = await progress.execute(\n \"Fetching DKIM configuration\",\n async () => {\n const response = await sesClient.send(\n new GetEmailIdentityCommand({ EmailIdentity: options.domain })\n );\n return response;\n }\n );\n\n const dkimTokens = identity.DkimAttributes?.Tokens || [];\n const dkimStatus = identity.DkimAttributes?.Status || \"PENDING\";\n\n progress.stop();\n\n if (dkimTokens.length === 0) {\n clack.outro(pc.yellow(\"No DKIM tokens found for this domain\"));\n return;\n }\n\n // Display DKIM status\n const statusLine = `${pc.bold(\"DKIM Status:\")} ${\n dkimStatus === \"SUCCESS\"\n ? pc.green(\"✓ Verified\")\n : pc.yellow(`⏱ ${dkimStatus}`)\n }`;\n clack.note(statusLine, \"Status\");\n\n // Display DKIM records\n console.log(`\\n${pc.bold(\"DNS Records to add:\")}\\n`);\n for (const token of dkimTokens) {\n console.log(`${pc.cyan(`${token}._domainkey.${options.domain}`)}`);\n console.log(` ${pc.dim(\"Type:\")} CNAME`);\n console.log(` ${pc.dim(\"Value:\")} ${token}.dkim.amazonses.com\\n`);\n }\n\n if (dkimStatus !== \"SUCCESS\") {\n console.log(\n `${pc.dim(\"After adding these records, run:\")} ${pc.cyan(`wraps email domains verify --domain ${options.domain}`)}\\n`\n );\n }\n\n // Track get-dkim success\n trackCommand(\"email:domains:get-dkim\", {\n success: true,\n dkim_status: dkimStatus,\n });\n } catch (error: any) {\n progress.stop();\n trackCommand(\"email:domains:get-dkim\", { success: false });\n if (error.name === \"NotFoundException\") {\n clack.log.error(`Domain ${options.domain} not found in SES`);\n console.log(\n `\\nRun ${pc.cyan(`wraps email domains add ${options.domain}`)} to add this domain.\\n`\n );\n process.exit(1);\n return; // Return after process.exit for testing\n }\n throw error;\n }\n}\n\n/**\n * Remove a domain from SES\n */\nexport async function removeDomain(options: {\n domain: string;\n force?: boolean; // Destructive operation\n}): Promise<void> {\n clack.intro(pc.bold(`Remove domain ${options.domain} from SES`));\n\n const progress = new DeploymentProgress();\n const region = await getAWSRegion();\n const sesClient = new SESv2Client({ region });\n\n try {\n // Check if domain exists\n await progress.execute(\"Checking if domain exists\", async () => {\n await sesClient.send(\n new GetEmailIdentityCommand({ EmailIdentity: options.domain })\n );\n });\n\n progress.stop();\n\n // Confirm deletion\n if (!options.force) {\n const shouldContinue = await clack.confirm({\n message: `Are you sure you want to remove ${pc.red(options.domain)} from SES?`,\n initialValue: false,\n });\n\n if (clack.isCancel(shouldContinue) || !shouldContinue) {\n clack.cancel(\"Operation cancelled\");\n process.exit(0);\n }\n }\n\n // Delete the identity\n const { DeleteEmailIdentityCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n await progress.execute(\"Removing domain from SES\", async () => {\n await sesClient.send(\n new DeleteEmailIdentityCommand({\n EmailIdentity: options.domain,\n })\n );\n });\n\n progress.stop();\n clack.outro(pc.green(`✓ Domain ${options.domain} removed successfully`));\n\n // Track remove domain success\n trackCommand(\"email:domains:remove\", {\n success: true,\n });\n trackFeature(\"domain_removed\", {});\n } catch (error: any) {\n progress.stop();\n trackCommand(\"email:domains:remove\", { success: false });\n if (error.name === \"NotFoundException\") {\n clack.log.error(`Domain ${options.domain} not found in SES`);\n process.exit(1);\n return; // Return after process.exit for testing\n }\n throw error;\n }\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { deployEmailStack } from \"../../infrastructure/email-stack.js\";\nimport {\n trackError,\n trackServiceDeployed,\n trackServiceInit,\n} from \"../../telemetry/events.js\";\nimport type {\n EmailStackConfig,\n InitOptions,\n WrapsEmailConfig,\n} from \"../../types/index.js\";\nimport { getCostSummary } from \"../../utils/email/costs.js\";\nimport { getPreset, validateConfig } from \"../../utils/email/presets.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { errors } from \"../../utils/shared/errors.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n createConnectionMetadata,\n loadConnectionMetadata,\n saveConnectionMetadata,\n} from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayPreview,\n displaySuccess,\n} from \"../../utils/shared/output.js\";\nimport {\n confirmDeploy,\n promptConfigPreset,\n promptCustomConfig,\n promptDomain,\n promptEstimatedVolume,\n promptProvider,\n promptRegion,\n promptVercelConfig,\n} from \"../../utils/shared/prompts.js\";\nimport { ensurePulumiInstalled } from \"../../utils/shared/pulumi.js\";\n\n/**\n * Init command - Deploy new email infrastructure\n */\nexport async function init(options: InitOptions): Promise<void> {\n const startTime = Date.now();\n\n clack.intro(\n pc.bold(\n options.preview\n ? \"Wraps Email Infrastructure Preview\"\n : \"Wraps Email Infrastructure Setup\"\n )\n );\n\n const progress = new DeploymentProgress();\n\n // 1. Check Pulumi CLI is installed (auto-install if missing)\n const wasAutoInstalled = await progress.execute(\n \"Checking Pulumi CLI installation\",\n async () => await ensurePulumiInstalled()\n );\n\n if (wasAutoInstalled) {\n progress.info(\"Pulumi CLI was automatically installed\");\n }\n\n // 2. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`Connected to AWS account: ${pc.cyan(identity.accountId)}`);\n\n // 3. Get configuration (from options or prompts)\n let provider = options.provider;\n if (!provider) {\n provider = await promptProvider();\n }\n\n let region = options.region;\n if (!region) {\n const defaultRegion = await getAWSRegion();\n region = await promptRegion(defaultRegion);\n }\n\n let domain = options.domain;\n if (!domain) {\n domain = await promptDomain();\n }\n\n // Get Vercel config if needed\n let vercelConfig;\n if (provider === \"vercel\") {\n vercelConfig = await promptVercelConfig();\n }\n\n // 4. Check if connection already exists\n const existingConnection = await loadConnectionMetadata(\n identity.accountId,\n region\n );\n if (existingConnection) {\n clack.log.warn(\n `Connection already exists for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n clack.log.info(`Created: ${existingConnection.timestamp}`);\n clack.log.info(`Use ${pc.cyan(\"wraps status\")} to view current setup`);\n clack.log.info(`Use ${pc.cyan(\"wraps upgrade\")} to add more features`);\n process.exit(0);\n }\n\n // 5. Configuration selection\n let preset = options.preset;\n if (!preset) {\n preset = await promptConfigPreset();\n }\n\n let emailConfig: WrapsEmailConfig;\n if (preset === \"custom\") {\n emailConfig = await promptCustomConfig();\n } else {\n emailConfig = getPreset(preset)!;\n\n // Prompt for email archiving (optional feature for presets)\n const { promptEmailArchiving } = await import(\n \"../../utils/shared/prompts.js\"\n );\n const archivingConfig = await promptEmailArchiving();\n emailConfig.emailArchiving = archivingConfig;\n }\n\n // Set domain if provided\n if (domain) {\n emailConfig.domain = domain;\n }\n\n // Get estimated volume for cost calculation\n const estimatedVolume = await promptEstimatedVolume();\n\n // Display cost summary\n progress.info(`\\n${pc.bold(\"Cost Estimate:\")}`);\n const costSummary = getCostSummary(emailConfig, estimatedVolume);\n clack.log.info(costSummary);\n\n // Validate configuration and show warnings\n const warnings = validateConfig(emailConfig);\n if (warnings.length > 0) {\n progress.info(`\\n${pc.yellow(pc.bold(\"Configuration Warnings:\"))}`);\n for (const warning of warnings) {\n clack.log.warn(warning);\n }\n }\n\n // 6. Create metadata to track deployment\n const metadata = createConnectionMetadata(\n identity.accountId,\n region,\n provider,\n emailConfig,\n preset === \"custom\" ? undefined : preset\n );\n if (vercelConfig) {\n metadata.vercel = vercelConfig;\n }\n\n // Confirm deployment (skip if --yes flag or --preview flag)\n if (!(options.yes || options.preview)) {\n const confirmed = await confirmDeploy();\n if (!confirmed) {\n clack.cancel(\"Deployment cancelled.\");\n process.exit(0);\n }\n }\n\n // 7. Build stack configuration\n const stackConfig: EmailStackConfig = {\n provider,\n region,\n vercel: vercelConfig,\n emailConfig,\n };\n\n // 8. Preview or Deploy infrastructure using Pulumi\n if (options.preview) {\n // PREVIEW MODE - show what would be created without deploying\n try {\n const previewResult = await progress.execute(\n \"Generating infrastructure preview\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName: `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n mailFromDomain: result.mailFromDomain,\n archiveArn: result.archiveArn,\n archivingEnabled: result.archivingEnabled,\n archiveRetention: result.archiveRetention,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Run preview instead of deployment\n const result = await stack.preview({ diff: true });\n return result;\n }\n );\n\n // Display preview results\n displayPreview({\n changeSummary: previewResult.changeSummary,\n costEstimate: costSummary,\n commandName: \"wraps email init\",\n });\n\n clack.outro(\n pc.green(\"Preview complete. Run without --preview to deploy.\")\n );\n\n // Track preview completion\n trackServiceInit(\"email\", true, {\n preset,\n provider,\n preview: true,\n duration_ms: Date.now() - startTime,\n });\n return;\n } catch (error: any) {\n trackError(\"PREVIEW_FAILED\", \"email:init\", { step: \"preview\" });\n if (error.message?.includes(\"stack is currently locked\")) {\n throw errors.stackLocked();\n }\n throw new Error(`Preview failed: ${error.message}`);\n }\n }\n\n // DEPLOY MODE - actually create infrastructure\n let outputs;\n try {\n outputs = await progress.execute(\n \"Deploying infrastructure (this may take 2-3 minutes)\",\n async () => {\n // Ensure Pulumi workspace directory exists\n await ensurePulumiWorkDir();\n\n // Run Pulumi inline program with local backend (no cloud required)\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName: `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n\n // Export outputs\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n mailFromDomain: result.mailFromDomain,\n archiveArn: result.archiveArn,\n archivingEnabled: result.archivingEnabled,\n archiveRetention: result.archiveRetention,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n // Use local file-based backend (no Pulumi Cloud login required)\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\", // Use empty passphrase for local state\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n // Set backend to local file system\n await stack.workspace.selectStack(\n `wraps-${identity.accountId}-${region}`\n );\n\n // Set AWS region\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Run the deployment\n const upResult = await stack.up({ onOutput: () => {} }); // Suppress Pulumi output\n\n // Get outputs\n const pulumiOutputs = upResult.outputs;\n\n return {\n roleArn: pulumiOutputs.roleArn?.value as string,\n configSetName: pulumiOutputs.configSetName?.value as\n | string\n | undefined,\n tableName: pulumiOutputs.tableName?.value as string | undefined,\n region: pulumiOutputs.region?.value as string,\n lambdaFunctions: pulumiOutputs.lambdaFunctions?.value as\n | string[]\n | undefined,\n domain: pulumiOutputs.domain?.value as string | undefined,\n dkimTokens: pulumiOutputs.dkimTokens?.value as string[] | undefined,\n customTrackingDomain: pulumiOutputs.customTrackingDomain?.value as\n | string\n | undefined,\n mailFromDomain: pulumiOutputs.mailFromDomain?.value as\n | string\n | undefined,\n archiveArn: pulumiOutputs.archiveArn?.value as string | undefined,\n archivingEnabled: pulumiOutputs.archivingEnabled?.value as\n | boolean\n | undefined,\n archiveRetention: pulumiOutputs.archiveRetention?.value as\n | string\n | undefined,\n };\n }\n );\n } catch (error: any) {\n // Track deployment failure\n trackServiceInit(\"email\", false, {\n preset,\n provider,\n duration_ms: Date.now() - startTime,\n });\n\n // Check if it's a lock file error\n if (error.message?.includes(\"stack is currently locked\")) {\n trackError(\"STACK_LOCKED\", \"email:init\", { step: \"deploy\" });\n throw errors.stackLocked();\n }\n\n trackError(\"DEPLOYMENT_FAILED\", \"email:init\", { step: \"deploy\" });\n throw new Error(`Pulumi deployment failed: ${error.message}`);\n }\n\n // 9. Save metadata for future upgrades and restore\n if (metadata.services.email) {\n metadata.services.email.pulumiStackName = `wraps-${identity.accountId}-${region}`;\n }\n await saveConnectionMetadata(metadata);\n\n progress.info(\"Connection metadata saved for upgrade and restore capability\");\n\n // 10. Check if Route53 hosted zone exists and create DNS records automatically\n let dnsAutoCreated = false;\n if (outputs.domain && outputs.dkimTokens && outputs.dkimTokens.length > 0) {\n const { findHostedZone, createDNSRecords } = await import(\n \"../../utils/email/route53.js\"\n );\n const hostedZone = await findHostedZone(outputs.domain, region);\n\n if (hostedZone) {\n try {\n progress.start(\"Creating DNS records in Route53\");\n await createDNSRecords(\n hostedZone.id,\n outputs.domain,\n outputs.dkimTokens,\n region,\n outputs.customTrackingDomain,\n outputs.mailFromDomain\n );\n progress.succeed(\"DNS records created in Route53\");\n dnsAutoCreated = true;\n } catch (error: any) {\n progress.fail(\"Failed to create DNS records in Route53\");\n clack.log.warn(`Could not auto-create DNS records: ${error.message}`);\n }\n }\n }\n\n // 11. Format DNS records if domain was provided and DNS wasn't auto-created\n const dnsRecords = [];\n if (\n outputs.domain &&\n outputs.dkimTokens &&\n outputs.dkimTokens.length > 0 &&\n !dnsAutoCreated\n ) {\n // Add DKIM CNAME records\n for (const token of outputs.dkimTokens) {\n dnsRecords.push({\n name: `${token}._domainkey.${outputs.domain}`,\n type: \"CNAME\",\n value: `${token}.dkim.amazonses.com`,\n });\n }\n }\n\n // 12. Display success message\n displaySuccess({\n roleArn: outputs.roleArn,\n configSetName: outputs.configSetName,\n region: outputs.region!,\n tableName: outputs.tableName,\n dnsRecords: dnsRecords.length > 0 ? dnsRecords : undefined,\n dnsAutoCreated,\n domain: outputs.domain,\n mailFromDomain: outputs.mailFromDomain,\n });\n\n // 13. Track successful deployment\n const duration = Date.now() - startTime;\n const enabledFeatures: string[] = [];\n if (emailConfig.tracking?.enabled) enabledFeatures.push(\"tracking\");\n if (emailConfig.suppressionList?.enabled)\n enabledFeatures.push(\"suppression_list\");\n if (emailConfig.eventTracking?.enabled)\n enabledFeatures.push(\"event_tracking\");\n if (emailConfig.eventTracking?.dynamoDBHistory)\n enabledFeatures.push(\"dynamodb_history\");\n if (emailConfig.dedicatedIp) enabledFeatures.push(\"dedicated_ip\");\n if (emailConfig.emailArchiving?.enabled)\n enabledFeatures.push(\"email_archiving\");\n\n trackServiceInit(\"email\", true, {\n preset,\n provider,\n features: enabledFeatures,\n duration_ms: duration,\n });\n\n trackServiceDeployed(\"email\", {\n duration_ms: duration,\n features: enabledFeatures,\n preset,\n });\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport {\n trackError,\n trackServiceRemoved,\n} from \"../../telemetry/events.js\";\nimport type { EmailRestoreOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { getPulumiWorkDir } from \"../../utils/shared/fs.js\";\nimport {\n deleteConnectionMetadata,\n loadConnectionMetadata,\n} from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayPreview,\n} from \"../../utils/shared/output.js\";\n\n/**\n * Restore command - Remove Wraps infrastructure (alias for destroy)\n *\n * Note: This command removes all Wraps-managed resources.\n * Since Wraps always creates NEW resources (wraps- prefix) and never modifies\n * existing infrastructure, there's nothing to \"restore\" - only to remove.\n */\nexport async function restore(options: EmailRestoreOptions): Promise<void> {\n const startTime = Date.now();\n\n clack.intro(\n pc.bold(\n options.preview\n ? \"Wraps Restore Preview\"\n : \"Wraps Restore - Remove Wraps Infrastructure\"\n )\n );\n\n clack.log.info(\n `${pc.yellow(\"Note:\")} This will remove all Wraps-managed infrastructure.`\n );\n clack.log.info(\n \"Your original AWS resources remain untouched (Wraps never modifies them).\\n\"\n );\n\n const progress = new DeploymentProgress();\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`Connected to AWS account: ${pc.cyan(identity.accountId)}`);\n\n // 2. Get region\n let region = options.region;\n if (!region) {\n const defaultRegion = await getAWSRegion();\n region = defaultRegion;\n }\n\n // 3. Load connection metadata\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n\n if (!metadata) {\n clack.log.error(\n `No Wraps connection found for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} or ${pc.cyan(\"wraps email connect\")} to create a connection first.`\n );\n process.exit(1);\n }\n\n progress.info(`Found connection created: ${metadata.timestamp}`);\n\n // 4. Display what will be removed\n console.log(\n `\\n${pc.bold(\"The following Wraps resources will be removed:\")}\\n`\n );\n\n if (metadata.services.email?.config.tracking?.enabled) {\n console.log(` ${pc.cyan(\"✓\")} Configuration Set (wraps-email-tracking)`);\n }\n if (metadata.services.email?.config.eventTracking?.dynamoDBHistory) {\n console.log(` ${pc.cyan(\"✓\")} DynamoDB Table (wraps-email-history)`);\n }\n if (metadata.services.email?.config.eventTracking?.enabled) {\n console.log(` ${pc.cyan(\"✓\")} EventBridge Rules`);\n console.log(` ${pc.cyan(\"✓\")} SQS Queues`);\n console.log(` ${pc.cyan(\"✓\")} Lambda Functions`);\n }\n console.log(` ${pc.cyan(\"✓\")} IAM Role (wraps-email-role)`);\n console.log(\"\");\n\n // 5. Confirm removal (skip if --force or --preview)\n if (!(options.force || options.preview)) {\n const confirmed = await clack.confirm({\n message: \"Proceed with removal? This cannot be undone.\",\n initialValue: false,\n });\n\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel(\"Removal cancelled.\");\n process.exit(0);\n }\n }\n\n // 6. Preview or Destroy Pulumi stack\n if (options.preview) {\n // PREVIEW MODE - show what would be destroyed without actually destroying\n if (metadata.services.email?.pulumiStackName) {\n try {\n const previewResult = await progress.execute(\n \"Generating removal preview\",\n async () => {\n const stack = await pulumi.automation.LocalWorkspace.selectStack(\n {\n stackName: metadata.services.email!.pulumiStackName!,\n projectName: \"wraps-email\",\n program: async () => {}, // Empty program for destroy\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n // Run preview to see what would be destroyed\n const result = await stack.preview({ diff: true });\n return result;\n }\n );\n\n // Display preview results\n displayPreview({\n changeSummary: previewResult.changeSummary,\n costEstimate: \"Monthly cost after removal: $0.00\",\n commandName: \"wraps email restore\",\n });\n\n clack.outro(\n pc.green(\n \"Preview complete. Run without --preview to remove infrastructure.\"\n )\n );\n\n // Track preview completion\n trackServiceRemoved(\"email\", {\n preview: true,\n duration_ms: Date.now() - startTime,\n });\n return;\n } catch (error: any) {\n trackError(\"PREVIEW_FAILED\", \"email:restore\", { step: \"preview\" });\n throw new Error(`Preview failed: ${error.message}`);\n }\n }\n return;\n }\n\n // DESTROY MODE - actually remove infrastructure\n if (metadata.services.email?.pulumiStackName) {\n await progress.execute(\"Removing Wraps infrastructure\", async () => {\n try {\n if (!metadata.services.email?.pulumiStackName) {\n throw new Error(\"No Pulumi stack name found in metadata\");\n }\n\n const stack = await pulumi.automation.LocalWorkspace.selectStack(\n {\n stackName: metadata.services.email.pulumiStackName,\n projectName: \"wraps-email\",\n program: async () => {}, // Empty program\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n // Destroy the stack\n await stack.destroy({ onOutput: () => {} });\n\n // Remove the stack\n await stack.workspace.removeStack(\n metadata.services.email.pulumiStackName\n );\n } catch (error: any) {\n trackError(\"DESTROY_FAILED\", \"email:restore\", { step: \"destroy\" });\n throw new Error(`Failed to destroy Pulumi stack: ${error.message}`);\n }\n });\n }\n\n // 7. Delete connection metadata\n await deleteConnectionMetadata(identity.accountId, region);\n\n progress.info(\"Connection metadata deleted\");\n\n // 8. Success message\n console.log(\n `\\n${pc.green(\"✓\")} ${pc.bold(\"Infrastructure removed successfully!\")}\\n`\n );\n console.log(\n `${pc.dim(\"All Wraps resources have been deleted from your AWS account.\")}`\n );\n console.log(`${pc.dim(\"Your original AWS resources remain unchanged.\")}\\n`);\n\n // 9. Track successful removal\n trackServiceRemoved(\"email\", {\n reason: \"user_initiated\",\n duration_ms: Date.now() - startTime,\n });\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { trackCommand } from \"../../telemetry/events.js\";\nimport type { StatusOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n listSESDomains,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n DeploymentProgress,\n displayStatus,\n} from \"../../utils/shared/output.js\";\n\n/**\n * Email Status command - Show current email infrastructure setup\n */\nexport async function emailStatus(_options: StatusOptions): Promise<void> {\n const startTime = Date.now();\n const progress = new DeploymentProgress();\n\n clack.intro(pc.bold(\"Wraps Email Status\"));\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Loading email infrastructure status\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region\n const region = await getAWSRegion();\n\n // 3. Try to load Pulumi stack\n let stackOutputs: any = {};\n try {\n // Ensure Pulumi workspace is configured (sets backend URL)\n await ensurePulumiWorkDir();\n\n const stack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName: `wraps-${identity.accountId}-${region}`,\n workDir: getPulumiWorkDir(),\n });\n\n stackOutputs = await stack.outputs();\n } catch (_error: any) {\n progress.stop();\n clack.log.error(\"No email infrastructure found\");\n console.log(\n `\\nRun ${pc.cyan(\"wraps email init\")} to deploy email infrastructure.\\n`\n );\n process.exit(1);\n }\n\n // 4. Get SES domains with DKIM tokens\n const domains = await listSESDomains(region);\n\n // 4a. Fetch DKIM tokens for each domain\n const { SESv2Client, GetEmailIdentityCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n const sesv2Client = new SESv2Client({ region });\n\n const domainsWithTokens = await Promise.all(\n domains.map(async (d) => {\n try {\n const identity = await sesv2Client.send(\n new GetEmailIdentityCommand({ EmailIdentity: d.domain })\n );\n return {\n domain: d.domain,\n status: d.verified ? (\"verified\" as const) : (\"pending\" as const),\n dkimTokens: identity.DkimAttributes?.Tokens || [],\n mailFromDomain: identity.MailFromAttributes?.MailFromDomain,\n mailFromStatus: identity.MailFromAttributes?.MailFromDomainStatus,\n };\n } catch (_error) {\n return {\n domain: d.domain,\n status: d.verified ? (\"verified\" as const) : (\"pending\" as const),\n dkimTokens: undefined,\n mailFromDomain: undefined,\n mailFromStatus: undefined,\n };\n }\n })\n );\n\n // 5. Determine integration level\n const integrationLevel = stackOutputs.configSetName\n ? \"enhanced\"\n : \"dashboard-only\";\n\n // 6. Display status\n progress.stop();\n displayStatus({\n integrationLevel: integrationLevel as \"dashboard-only\" | \"enhanced\",\n region,\n domains: domainsWithTokens,\n resources: {\n roleArn: stackOutputs.roleArn?.value,\n configSetName: stackOutputs.configSetName?.value,\n tableName: stackOutputs.tableName?.value,\n lambdaFunctions: stackOutputs.lambdaFunctions?.value?.length || 0,\n snsTopics: integrationLevel === \"enhanced\" ? 1 : 0,\n archiveArn: stackOutputs.archiveArn?.value,\n archivingEnabled: stackOutputs.archivingEnabled?.value,\n archiveRetention: stackOutputs.archiveRetention?.value,\n },\n tracking: stackOutputs.customTrackingDomain?.value\n ? {\n customTrackingDomain: stackOutputs.customTrackingDomain?.value,\n httpsEnabled: stackOutputs.httpsTrackingEnabled?.value,\n cloudFrontDomain: stackOutputs.cloudFrontDomain?.value,\n }\n : undefined,\n });\n\n // 7. Track status command\n trackCommand(\"email:status\", {\n success: true,\n domain_count: domainsWithTokens.length,\n integration_level: integrationLevel,\n duration_ms: Date.now() - startTime,\n });\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { deployEmailStack } from \"../../infrastructure/email-stack.js\";\nimport {\n trackError,\n trackServiceUpgrade,\n} from \"../../telemetry/events.js\";\nimport type {\n EmailStackConfig,\n UpgradeOptions,\n WrapsEmailConfig,\n} from \"../../types/index.js\";\nimport { calculateCosts, formatCost } from \"../../utils/email/costs.js\";\nimport { getAllPresetInfo, getPreset } from \"../../utils/email/presets.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { errors } from \"../../utils/shared/errors.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n applyConfigUpdates,\n loadConnectionMetadata,\n saveConnectionMetadata,\n updateEmailConfig,\n} from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayPreview,\n displaySuccess,\n} from \"../../utils/shared/output.js\";\nimport { promptVercelConfig } from \"../../utils/shared/prompts.js\";\nimport { ensurePulumiInstalled } from \"../../utils/shared/pulumi.js\";\n\n/**\n * Upgrade command - Enhance existing Wraps infrastructure\n */\nexport async function upgrade(options: UpgradeOptions): Promise<void> {\n const startTime = Date.now();\n let upgradeAction: string | symbol = \"\";\n\n clack.intro(\n pc.bold(\n options.preview\n ? \"Wraps Upgrade Preview\"\n : \"Wraps Upgrade - Enhance Your Email Infrastructure\"\n )\n );\n\n const progress = new DeploymentProgress();\n\n // 1. Check Pulumi CLI is installed\n const wasAutoInstalled = await progress.execute(\n \"Checking Pulumi CLI installation\",\n async () => await ensurePulumiInstalled()\n );\n\n if (wasAutoInstalled) {\n progress.info(\"Pulumi CLI was automatically installed\");\n }\n\n // 2. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`Connected to AWS account: ${pc.cyan(identity.accountId)}`);\n\n // 3. Get region\n let region = options.region;\n if (!region) {\n const defaultRegion = await getAWSRegion();\n region = defaultRegion;\n }\n\n // 4. Load existing connection metadata\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n\n if (!metadata) {\n clack.log.error(\n `No Wraps connection found for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} to create new infrastructure or ${pc.cyan(\"wraps email connect\")} to connect existing.`\n );\n process.exit(1);\n }\n\n progress.info(`Found existing connection created: ${metadata.timestamp}`);\n\n // 5. Display current configuration\n console.log(`\\n${pc.bold(\"Current Configuration:\")}\\n`);\n\n if (metadata.services.email?.preset) {\n console.log(` Preset: ${pc.cyan(metadata.services.email?.preset)}`);\n } else {\n console.log(` Preset: ${pc.cyan(\"custom\")}`);\n }\n\n const config = metadata.services.email?.config;\n\n if (!config) {\n clack.log.error(\"No email configuration found in metadata\");\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} to create new infrastructure.`\n );\n process.exit(1);\n }\n\n // Show sending domain if configured\n if (config.domain) {\n console.log(` Sending Domain: ${pc.cyan(config.domain)}`);\n }\n\n if (config.tracking?.enabled) {\n console.log(` ${pc.green(\"✓\")} Open & Click Tracking`);\n if (config.tracking.customRedirectDomain) {\n console.log(\n ` ${pc.dim(\"└─\")} Custom domain: ${pc.cyan(config.tracking.customRedirectDomain)}`\n );\n }\n }\n\n if (config.suppressionList?.enabled) {\n console.log(` ${pc.green(\"✓\")} Bounce/Complaint Suppression`);\n }\n\n if (config.eventTracking?.enabled) {\n console.log(` ${pc.green(\"✓\")} Event Tracking (EventBridge)`);\n if (config.eventTracking.dynamoDBHistory) {\n console.log(\n ` ${pc.dim(\"└─\")} Email History: ${pc.cyan(config.eventTracking.archiveRetention || \"90days\")}`\n );\n }\n }\n\n if (config.dedicatedIp) {\n console.log(` ${pc.green(\"✓\")} Dedicated IP Address`);\n }\n\n if (config.emailArchiving?.enabled) {\n const retentionLabel =\n {\n \"7days\": \"7 days\",\n \"30days\": \"30 days\",\n \"90days\": \"90 days\",\n \"3months\": \"3 months\",\n \"6months\": \"6 months\",\n \"9months\": \"9 months\",\n \"1year\": \"1 year\",\n \"18months\": \"18 months\",\n \"2years\": \"2 years\",\n \"30months\": \"30 months\",\n \"3years\": \"3 years\",\n \"4years\": \"4 years\",\n \"5years\": \"5 years\",\n \"6years\": \"6 years\",\n \"7years\": \"7 years\",\n \"8years\": \"8 years\",\n \"9years\": \"9 years\",\n \"10years\": \"10 years\",\n indefinite: \"indefinite\",\n permanent: \"permanent\",\n }[config.emailArchiving.retention] || \"90 days\";\n console.log(` ${pc.green(\"✓\")} Email Archiving (${retentionLabel})`);\n }\n\n // Calculate current cost\n const currentCostData = calculateCosts(config, 50_000); // Assume 50k emails/mo for estimate\n console.log(\n `\\n Estimated Cost: ${pc.cyan(`~${formatCost(currentCostData.total.monthly)}/mo`)}`\n );\n\n console.log(\"\");\n\n // 6. Prompt for upgrade action\n upgradeAction = await clack.select({\n message: \"What would you like to do?\",\n options: [\n {\n value: \"preset\",\n label: \"Upgrade to a different preset\",\n hint: \"Starter → Production → Enterprise\",\n },\n {\n value: \"archiving\",\n label: config.emailArchiving?.enabled\n ? \"Change email archiving settings\"\n : \"Enable email archiving\",\n hint: config.emailArchiving?.enabled\n ? \"Update retention or disable\"\n : \"Store full email content with HTML\",\n },\n {\n value: \"tracking-domain\",\n label: \"Add/change custom tracking domain\",\n hint: \"Use your own domain for email links\",\n },\n {\n value: \"retention\",\n label: \"Change email history retention\",\n hint: \"7 days, 30 days, 90 days, 6 months, 1 year, 18 months\",\n },\n {\n value: \"events\",\n label: \"Customize tracked event types\",\n hint: \"Choose which SES events to track\",\n },\n {\n value: \"dedicated-ip\",\n label: \"Enable dedicated IP address\",\n hint: \"Requires 100k+ emails/day ($50-100/mo)\",\n },\n {\n value: \"custom\",\n label: \"Custom configuration\",\n hint: \"Modify multiple settings at once\",\n },\n ],\n });\n\n if (clack.isCancel(upgradeAction)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n let updatedConfig: WrapsEmailConfig = { ...config };\n let newPreset: string | undefined = metadata.services.email?.preset;\n\n // 7. Handle upgrade action\n switch (upgradeAction) {\n case \"preset\": {\n // Show available presets\n const presets = getAllPresetInfo();\n const currentPresetIdx = presets.findIndex(\n (p) => p.name.toLowerCase() === metadata.services.email?.preset\n );\n\n const availablePresets = presets\n .map((p, idx) => ({\n value: p.name.toLowerCase(),\n label: `${p.name} - ${p.description}`,\n hint: `${p.volume} | Est. ${p.estimatedCost}/mo`,\n disabled:\n currentPresetIdx >= 0 && idx <= currentPresetIdx\n ? \"Current or lower tier\"\n : undefined,\n }))\n .filter((p) => !p.disabled);\n\n if (availablePresets.length === 0) {\n clack.log.warn(\"Already on highest preset (Enterprise)\");\n process.exit(0);\n }\n\n const selectedPreset = await clack.select({\n message: \"Select new preset:\",\n options: availablePresets,\n });\n\n if (clack.isCancel(selectedPreset)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n // Get preset config but preserve user-customized fields from existing config\n const presetConfig = getPreset(selectedPreset as any)!;\n\n // Apply preset updates to existing config (preserves user customizations)\n updatedConfig = applyConfigUpdates(config, presetConfig);\n newPreset = selectedPreset as string;\n break;\n }\n\n case \"archiving\": {\n if (config.emailArchiving?.enabled) {\n // Already enabled - allow changing retention or disabling\n const archivingAction = await clack.select({\n message: \"What would you like to do with email archiving?\",\n options: [\n {\n value: \"change-retention\",\n label: \"Change retention period\",\n hint: `Current: ${config.emailArchiving.retention}`,\n },\n {\n value: \"disable\",\n label: \"Disable email archiving\",\n hint: \"Stop storing full email content\",\n },\n ],\n });\n\n if (clack.isCancel(archivingAction)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n if (archivingAction === \"disable\") {\n const confirmDisable = await clack.confirm({\n message:\n \"Are you sure? Existing archived emails will remain, but new emails won't be archived.\",\n initialValue: false,\n });\n\n if (clack.isCancel(confirmDisable) || !confirmDisable) {\n clack.cancel(\"Archiving not disabled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n emailArchiving: {\n enabled: false,\n retention: config.emailArchiving.retention,\n },\n };\n } else {\n // Change retention\n const retention = await clack.select({\n message: \"Email archive retention period:\",\n options: [\n {\n value: \"7days\",\n label: \"7 days\",\n hint: \"~$1-2/mo for 10k emails\",\n },\n {\n value: \"30days\",\n label: \"30 days\",\n hint: \"~$2-4/mo for 10k emails\",\n },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"~$5-10/mo for 10k emails\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"~$15-25/mo for 10k emails\",\n },\n {\n value: \"1year\",\n label: \"1 year\",\n hint: \"~$25-40/mo for 10k emails\",\n },\n {\n value: \"18months\",\n label: \"18 months\",\n hint: \"~$35-60/mo for 10k emails\",\n },\n ],\n initialValue: config.emailArchiving.retention,\n });\n\n if (clack.isCancel(retention)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n emailArchiving: {\n enabled: true,\n retention: retention as any,\n },\n };\n }\n } else {\n // Not enabled - prompt to enable with retention selection\n const enableArchiving = await clack.confirm({\n message:\n \"Enable email archiving? (Store full email content with HTML for viewing)\",\n initialValue: true,\n });\n\n if (clack.isCancel(enableArchiving)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n if (!enableArchiving) {\n clack.log.info(\"Email archiving not enabled.\");\n process.exit(0);\n }\n\n const retention = await clack.select({\n message: \"Email archive retention period:\",\n options: [\n {\n value: \"7days\",\n label: \"7 days\",\n hint: \"~$1-2/mo for 10k emails\",\n },\n {\n value: \"30days\",\n label: \"30 days\",\n hint: \"~$2-4/mo for 10k emails\",\n },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"~$5-10/mo for 10k emails\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"~$15-25/mo for 10k emails\",\n },\n {\n value: \"1year\",\n label: \"1 year\",\n hint: \"~$25-40/mo for 10k emails\",\n },\n {\n value: \"18months\",\n label: \"18 months\",\n hint: \"~$35-60/mo for 10k emails\",\n },\n ],\n initialValue: \"90days\",\n });\n\n if (clack.isCancel(retention)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n clack.log.info(\n pc.dim(\n \"Archiving stores full RFC 822 emails with HTML, attachments, and headers\"\n )\n );\n clack.log.info(\n pc.dim(\n \"Cost: $2/GB ingestion + $0.19/GB/month storage (~50KB per email)\"\n )\n );\n\n updatedConfig = {\n ...config,\n emailArchiving: {\n enabled: true,\n retention: retention as any,\n },\n };\n }\n newPreset = undefined; // Custom config\n break;\n }\n\n case \"tracking-domain\": {\n // First, check if a sending identity (domain) is configured and verified\n if (!config.domain) {\n clack.log.error(\n \"No sending domain configured. You must configure a sending domain before adding a custom tracking domain.\"\n );\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} to set up a sending domain first.`\n );\n process.exit(1);\n }\n\n // Verify that the sending identity is verified\n const { listSESDomains } = await import(\"../../utils/shared/aws.js\");\n const domains = await progress.execute(\n \"Checking domain verification status\",\n async () => await listSESDomains(region)\n );\n\n const sendingDomain = domains.find((d) => d.domain === config.domain);\n\n if (!sendingDomain?.verified) {\n clack.log.error(\n `Sending domain ${pc.cyan(config.domain)} is not verified.`\n );\n clack.log.info(\n \"You must verify your sending domain before adding a custom tracking domain.\"\n );\n clack.log.info(\n `Use ${pc.cyan(\"wraps email verify\")} to check DNS records and complete verification.`\n );\n process.exit(1);\n }\n\n progress.info(\n `Sending domain ${pc.cyan(config.domain)} is verified ${pc.green(\"✓\")}`\n );\n\n const trackingDomain = await clack.text({\n message: \"Custom tracking redirect domain:\",\n placeholder: \"track.yourdomain.com\",\n initialValue: config.tracking?.customRedirectDomain || \"\",\n validate: (value) => {\n if (value && !/^[a-z0-9.-]+\\.[a-z]{2,}$/.test(value)) {\n return \"Please enter a valid domain\";\n }\n },\n });\n\n if (clack.isCancel(trackingDomain)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n // Ask if HTTPS tracking should be enabled\n const enableHttps = await clack.confirm({\n message: \"Enable HTTPS tracking with CloudFront + SSL certificate?\",\n initialValue: true,\n });\n\n if (clack.isCancel(enableHttps)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n if (enableHttps) {\n clack.log.info(\n pc.dim(\n \"HTTPS tracking creates a CloudFront distribution with an SSL certificate.\"\n )\n );\n clack.log.info(\n pc.dim(\n \"This ensures all tracking links use secure HTTPS connections.\"\n )\n );\n\n // Check if domain has Route53 hosted zone\n const { findHostedZone } = await import(\"../../utils/email/route53.js\");\n const hostedZone = await progress.execute(\n \"Checking for Route53 hosted zone\",\n async () =>\n await findHostedZone(trackingDomain || config.domain!, region)\n );\n\n if (hostedZone) {\n progress.info(\n `Found Route53 hosted zone: ${pc.cyan(hostedZone.name)} ${pc.green(\"✓\")}`\n );\n clack.log.info(\n pc.dim(\n \"DNS records (SSL certificate validation + CloudFront) will be created automatically.\"\n )\n );\n } else {\n clack.log.warn(\n `No Route53 hosted zone found for ${pc.cyan(trackingDomain || config.domain!)}`\n );\n clack.log.info(\n pc.dim(\n \"You'll need to manually create DNS records for SSL certificate validation and CloudFront.\"\n )\n );\n clack.log.info(\n pc.dim(\"DNS record details will be shown after deployment.\")\n );\n }\n\n const confirmHttps = await clack.confirm({\n message: hostedZone\n ? \"Proceed with automatic HTTPS setup?\"\n : \"Proceed with manual HTTPS setup (requires DNS configuration)?\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirmHttps) || !confirmHttps) {\n clack.log.info(\"HTTPS tracking not enabled. Using HTTP tracking.\");\n updatedConfig = {\n ...config,\n tracking: {\n ...config.tracking,\n enabled: true,\n customRedirectDomain: trackingDomain || undefined,\n httpsEnabled: false,\n },\n };\n } else {\n updatedConfig = {\n ...config,\n tracking: {\n ...config.tracking,\n enabled: true,\n customRedirectDomain: trackingDomain || undefined,\n httpsEnabled: true,\n },\n };\n }\n } else {\n clack.log.info(\n pc.dim(\n \"Using HTTP tracking (standard). Links will use http:// protocol.\"\n )\n );\n updatedConfig = {\n ...config,\n tracking: {\n ...config.tracking,\n enabled: true,\n customRedirectDomain: trackingDomain || undefined,\n httpsEnabled: false,\n },\n };\n }\n\n newPreset = undefined; // Custom config\n break;\n }\n\n case \"retention\": {\n const retention = await clack.select({\n message: \"Email history retention period (event data in DynamoDB):\",\n options: [\n { value: \"7days\", label: \"7 days\", hint: \"Minimal storage cost\" },\n { value: \"30days\", label: \"30 days\", hint: \"Development/testing\" },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"Standard retention\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"Extended retention\",\n },\n { value: \"1year\", label: \"1 year\", hint: \"Compliance requirements\" },\n {\n value: \"18months\",\n label: \"18 months\",\n hint: \"Long-term retention\",\n },\n ],\n initialValue: config.eventTracking?.archiveRetention || \"90days\",\n });\n\n if (clack.isCancel(retention)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n clack.log.info(\n pc.dim(\n \"Note: This is for event data (sent, delivered, opened, etc.) stored in DynamoDB.\"\n )\n );\n clack.log.info(\n pc.dim(\n \"For full email content storage, use 'Enable email archiving' option.\"\n )\n );\n\n updatedConfig = {\n ...config,\n eventTracking: {\n ...config.eventTracking,\n enabled: true,\n dynamoDBHistory: true,\n archiveRetention: retention as any,\n },\n };\n newPreset = undefined; // Custom config\n break;\n }\n\n case \"events\": {\n const selectedEvents = await clack.multiselect({\n message: \"Select SES event types to track:\",\n options: [\n { value: \"SEND\", label: \"Send\", hint: \"Email sent to SES\" },\n {\n value: \"DELIVERY\",\n label: \"Delivery\",\n hint: \"Email delivered successfully\",\n },\n { value: \"OPEN\", label: \"Open\", hint: \"Recipient opened email\" },\n { value: \"CLICK\", label: \"Click\", hint: \"Recipient clicked link\" },\n { value: \"BOUNCE\", label: \"Bounce\", hint: \"Email bounced\" },\n {\n value: \"COMPLAINT\",\n label: \"Complaint\",\n hint: \"Spam complaint received\",\n },\n { value: \"REJECT\", label: \"Reject\", hint: \"Email rejected by SES\" },\n {\n value: \"RENDERING_FAILURE\",\n label: \"Rendering Failure\",\n hint: \"Template rendering failed\",\n },\n {\n value: \"DELIVERY_DELAY\",\n label: \"Delivery Delay\",\n hint: \"Temporary delivery delay\",\n },\n {\n value: \"SUBSCRIPTION\",\n label: \"Subscription\",\n hint: \"List subscription event\",\n },\n ],\n initialValues: config.eventTracking?.events || [\n \"SEND\",\n \"DELIVERY\",\n \"OPEN\",\n \"CLICK\",\n \"BOUNCE\",\n \"COMPLAINT\",\n ],\n required: true,\n });\n\n if (clack.isCancel(selectedEvents)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n eventTracking: {\n ...config.eventTracking,\n enabled: true,\n events: selectedEvents as any,\n },\n };\n newPreset = undefined; // Custom config\n break;\n }\n\n case \"dedicated-ip\": {\n const confirmed = await clack.confirm({\n message:\n \"Enable dedicated IP? (Requires 100k+ emails/day, adds ~$50-100/mo)\",\n initialValue: false,\n });\n\n if (clack.isCancel(confirmed)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n if (!confirmed) {\n clack.log.info(\"Dedicated IP not enabled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n dedicatedIp: true,\n };\n newPreset = undefined; // Custom config\n break;\n }\n\n case \"custom\": {\n // Full custom configuration\n const { promptCustomConfig } = await import(\n \"../../utils/shared/prompts.js\"\n );\n\n // Pass existing config to preserve values\n const customConfig = await promptCustomConfig(config);\n\n // Apply custom config updates to existing config (preserves user-customized fields)\n updatedConfig = applyConfigUpdates(config, customConfig);\n newPreset = undefined;\n break;\n }\n }\n\n // 8. Show cost comparison\n const newCostData = calculateCosts(updatedConfig, 50_000);\n const costDiff = newCostData.total.monthly - currentCostData.total.monthly;\n\n console.log(`\\n${pc.bold(\"Cost Impact:\")}`);\n console.log(\n ` Current: ${pc.cyan(`${formatCost(currentCostData.total.monthly)}/mo`)}`\n );\n console.log(\n ` New: ${pc.cyan(`${formatCost(newCostData.total.monthly)}/mo`)}`\n );\n if (costDiff > 0) {\n console.log(` Change: ${pc.yellow(`+${formatCost(costDiff)}/mo`)}`);\n } else if (costDiff < 0) {\n console.log(\n ` Change: ${pc.green(`${formatCost(Math.abs(costDiff))}/mo`)}`\n );\n }\n console.log(\"\");\n\n // 9. Confirm upgrade (skip if --yes or --preview)\n if (!(options.yes || options.preview)) {\n const confirmed = await clack.confirm({\n message: \"Proceed with upgrade?\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n }\n\n // 10. Get Vercel config if needed and not already stored\n let vercelConfig;\n if (metadata.provider === \"vercel\" && !metadata.vercel) {\n vercelConfig = await promptVercelConfig();\n } else if (metadata.provider === \"vercel\") {\n vercelConfig = metadata.vercel;\n }\n\n // 11. Build stack configuration\n const stackConfig: EmailStackConfig = {\n provider: metadata.provider,\n region,\n vercel: vercelConfig,\n emailConfig: updatedConfig,\n };\n\n // 12. Preview or Update Pulumi stack\n if (options.preview) {\n // PREVIEW MODE - show what would be changed without deploying\n try {\n const previewResult = await progress.execute(\n \"Generating upgrade preview\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName:\n metadata.services.email?.pulumiStackName ||\n `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n httpsTrackingEnabled: result.httpsTrackingEnabled,\n cloudFrontDomain: result.cloudFrontDomain,\n acmCertificateValidationRecords:\n result.acmCertificateValidationRecords,\n archiveArn: result.archiveArn,\n archivingEnabled: result.archivingEnabled,\n archiveRetention: result.archiveRetention,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Refresh state to sync with AWS before previewing\n await stack.refresh({ onOutput: () => {} });\n\n // Run preview instead of deployment\n const result = await stack.preview({ diff: true });\n return result;\n }\n );\n\n // Build cost comparison string\n const costComparison = [\n `Current: ${formatCost(currentCostData.total.monthly)}/mo`,\n `After upgrade: ${formatCost(newCostData.total.monthly)}/mo`,\n costDiff > 0\n ? `Change: +${formatCost(costDiff)}/mo`\n : costDiff < 0\n ? `Change: -${formatCost(Math.abs(costDiff))}/mo`\n : \"Change: No cost difference\",\n ].join(\"\\n\");\n\n // Display preview results\n displayPreview({\n changeSummary: previewResult.changeSummary,\n costEstimate: costComparison,\n commandName: \"wraps email upgrade\",\n });\n\n clack.outro(\n pc.green(\"Preview complete. Run without --preview to upgrade.\")\n );\n\n // Track preview completion\n trackServiceUpgrade(\"email\", {\n from_preset: metadata.services.email?.preset,\n to_preset: newPreset,\n preview: true,\n action: typeof upgradeAction === \"string\" ? upgradeAction : undefined,\n duration_ms: Date.now() - startTime,\n });\n return;\n } catch (error: any) {\n trackError(\"PREVIEW_FAILED\", \"email:upgrade\", { step: \"preview\" });\n if (error.message?.includes(\"stack is currently locked\")) {\n throw errors.stackLocked();\n }\n throw new Error(`Preview failed: ${error.message}`);\n }\n }\n\n // DEPLOY MODE - actually update infrastructure\n let outputs;\n try {\n outputs = await progress.execute(\n \"Updating Wraps infrastructure (this may take 2-3 minutes)\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName:\n metadata.services.email?.pulumiStackName ||\n `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n httpsTrackingEnabled: result.httpsTrackingEnabled,\n cloudFrontDomain: result.cloudFrontDomain,\n acmCertificateValidationRecords:\n result.acmCertificateValidationRecords,\n archiveArn: result.archiveArn,\n archivingEnabled: result.archivingEnabled,\n archiveRetention: result.archiveRetention,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.workspace.selectStack(\n metadata.services.email?.pulumiStackName ||\n `wraps-${identity.accountId}-${region}`\n );\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Refresh state to sync with AWS before upgrading\n // This ensures Pulumi knows about resources that already exist\n await stack.refresh({ onOutput: () => {} });\n\n // Pulumi will automatically detect changes and only update what's needed\n const upResult = await stack.up({ onOutput: () => {} });\n const pulumiOutputs = upResult.outputs;\n\n return {\n roleArn: pulumiOutputs.roleArn?.value as string,\n configSetName: pulumiOutputs.configSetName?.value as\n | string\n | undefined,\n tableName: pulumiOutputs.tableName?.value as string | undefined,\n region: pulumiOutputs.region?.value as string,\n lambdaFunctions: pulumiOutputs.lambdaFunctions?.value as\n | string[]\n | undefined,\n domain: pulumiOutputs.domain?.value as string | undefined,\n dkimTokens: pulumiOutputs.dkimTokens?.value as string[] | undefined,\n customTrackingDomain: pulumiOutputs.customTrackingDomain?.value as\n | string\n | undefined,\n httpsTrackingEnabled: pulumiOutputs.httpsTrackingEnabled?.value as\n | boolean\n | undefined,\n cloudFrontDomain: pulumiOutputs.cloudFrontDomain?.value as\n | string\n | undefined,\n acmCertificateValidationRecords: pulumiOutputs\n .acmCertificateValidationRecords?.value as\n | Array<{ name: string; type: string; value: string }>\n | undefined,\n archiveArn: pulumiOutputs.archiveArn?.value as string | undefined,\n archivingEnabled: pulumiOutputs.archivingEnabled?.value as\n | boolean\n | undefined,\n archiveRetention: pulumiOutputs.archiveRetention?.value as\n | string\n | undefined,\n };\n }\n );\n } catch (error: any) {\n // Track upgrade failure\n trackServiceUpgrade(\"email\", {\n from_preset: metadata.services.email?.preset,\n to_preset: newPreset,\n action: typeof upgradeAction === \"string\" ? upgradeAction : undefined,\n duration_ms: Date.now() - startTime,\n });\n\n // Check if it's a lock file error\n if (error.message?.includes(\"stack is currently locked\")) {\n trackError(\"STACK_LOCKED\", \"email:upgrade\", { step: \"deploy\" });\n throw errors.stackLocked();\n }\n\n trackError(\"UPGRADE_FAILED\", \"email:upgrade\", { step: \"deploy\" });\n throw new Error(`Pulumi upgrade failed: ${error.message}`);\n }\n\n // 13. Create DNS records in Route53 (if hosted zone exists)\n if (outputs.domain && outputs.dkimTokens && outputs.dkimTokens.length > 0) {\n const { findHostedZone, createDNSRecords } = await import(\n \"../../utils/email/route53.js\"\n );\n const hostedZone = await findHostedZone(outputs.domain, region);\n\n if (hostedZone) {\n try {\n progress.start(\"Creating DNS records in Route53\");\n\n // Determine mailFromDomain - use updatedConfig if available, otherwise construct default\n const mailFromDomain =\n updatedConfig.mailFromDomain || `mail.${outputs.domain}`;\n\n await createDNSRecords(\n hostedZone.id,\n outputs.domain,\n outputs.dkimTokens,\n region,\n outputs.customTrackingDomain,\n mailFromDomain,\n outputs.cloudFrontDomain\n );\n progress.succeed(\"DNS records created in Route53\");\n } catch (error: any) {\n progress.fail(\n `Failed to create DNS records automatically: ${error.message}`\n );\n progress.info(\n \"You can manually add the required DNS records shown below\"\n );\n }\n }\n }\n\n // 14. Update metadata\n updateEmailConfig(metadata, updatedConfig);\n if (metadata.services.email) {\n metadata.services.email.preset = newPreset as any;\n }\n await saveConnectionMetadata(metadata);\n\n progress.info(\"Connection metadata updated\");\n\n // 15. Format tracking domain DNS records if custom tracking domain was added\n const trackingDomainDnsRecords = [];\n const acmValidationRecords = [];\n\n if (outputs.customTrackingDomain) {\n // For HTTPS tracking, only show CNAME if CloudFront exists\n // For HTTP tracking, point to SES tracking endpoint\n if (outputs.httpsTrackingEnabled) {\n // Only add tracking domain CNAME if CloudFront is created\n if (outputs.cloudFrontDomain) {\n trackingDomainDnsRecords.push({\n name: outputs.customTrackingDomain,\n type: \"CNAME\",\n value: outputs.cloudFrontDomain,\n });\n }\n } else {\n // HTTP tracking - use SES tracking endpoint\n trackingDomainDnsRecords.push({\n name: outputs.customTrackingDomain,\n type: \"CNAME\",\n value: `r.${outputs.region}.awstrack.me`,\n });\n }\n }\n\n // Add ACM certificate validation records if HTTPS tracking is enabled\n if (outputs.httpsTrackingEnabled && outputs.acmCertificateValidationRecords) {\n acmValidationRecords.push(...outputs.acmCertificateValidationRecords);\n }\n\n // Check if HTTPS tracking was enabled but CloudFront wasn't created (manual DNS validation needed)\n const needsCertificateValidation =\n outputs.httpsTrackingEnabled &&\n acmValidationRecords.length > 0 &&\n !outputs.cloudFrontDomain;\n\n // 15. Display success message\n displaySuccess({\n roleArn: outputs.roleArn,\n configSetName: outputs.configSetName,\n region: outputs.region!,\n tableName: outputs.tableName,\n trackingDomainDnsRecords:\n trackingDomainDnsRecords.length > 0\n ? trackingDomainDnsRecords\n : undefined,\n acmValidationRecords:\n acmValidationRecords.length > 0 ? acmValidationRecords : undefined,\n customTrackingDomain: outputs.customTrackingDomain,\n httpsTrackingEnabled: outputs.httpsTrackingEnabled,\n });\n\n // Show what was upgraded\n console.log(`\\n${pc.green(\"✓\")} ${pc.bold(\"Upgrade complete!\")}\\n`);\n\n if (upgradeAction === \"preset\" && newPreset) {\n console.log(\n `Upgraded to ${pc.cyan(newPreset)} preset (${pc.green(`${formatCost(newCostData.total.monthly)}/mo`)})\\n`\n );\n } else {\n console.log(\n `Updated configuration (${pc.green(`${formatCost(newCostData.total.monthly)}/mo`)})\\n`\n );\n }\n\n // Show next steps for HTTPS tracking if certificate validation is pending\n if (needsCertificateValidation) {\n console.log(pc.bold(\"⚠️ HTTPS Tracking - Next Steps:\\n\"));\n console.log(\n \" 1. Add the SSL certificate validation DNS record shown above to your DNS provider\"\n );\n console.log(\n \" 2. Wait for DNS propagation and certificate validation (5-30 minutes)\"\n );\n console.log(\n ` 3. Run ${pc.cyan(\"wraps email upgrade\")} again to complete CloudFront setup\\n`\n );\n console.log(\n pc.dim(\n \" Note: CloudFront distribution will be created once the certificate is validated.\\n\"\n )\n );\n } else if (outputs.httpsTrackingEnabled && outputs.cloudFrontDomain) {\n console.log(\n pc.green(\"✓\") +\n \" \" +\n pc.bold(\"HTTPS tracking is fully configured and ready to use!\\n\")\n );\n }\n\n // 16. Track successful upgrade\n const enabledFeatures: string[] = [];\n if (updatedConfig.tracking?.enabled) enabledFeatures.push(\"tracking\");\n if (updatedConfig.suppressionList?.enabled)\n enabledFeatures.push(\"suppression_list\");\n if (updatedConfig.eventTracking?.enabled)\n enabledFeatures.push(\"event_tracking\");\n if (updatedConfig.eventTracking?.dynamoDBHistory)\n enabledFeatures.push(\"dynamodb_history\");\n if (updatedConfig.dedicatedIp) enabledFeatures.push(\"dedicated_ip\");\n if (updatedConfig.emailArchiving?.enabled)\n enabledFeatures.push(\"email_archiving\");\n\n trackServiceUpgrade(\"email\", {\n from_preset: metadata.services.email?.preset,\n to_preset: newPreset,\n added_features: enabledFeatures,\n action: typeof upgradeAction === \"string\" ? upgradeAction : undefined,\n duration_ms: Date.now() - startTime,\n });\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport getPort from \"get-port\";\nimport open from \"open\";\nimport pc from \"picocolors\";\nimport { startConsoleServer } from \"../../console/server.js\";\nimport { trackCommand } from \"../../telemetry/events.js\";\nimport type { DashboardOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\n\n/**\n * Dashboard command - Start local web dashboard\n */\nexport async function dashboard(options: DashboardOptions): Promise<void> {\n clack.intro(pc.bold(\"Wraps Dashboard\"));\n\n const progress = new DeploymentProgress();\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region\n const region = await getAWSRegion();\n\n // 3. Load stack outputs to get IAM role ARN\n let stackOutputs: any = {};\n try {\n // Ensure Pulumi workspace is configured (sets backend URL)\n await ensurePulumiWorkDir();\n\n const stack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName: `wraps-${identity.accountId}-${region}`,\n workDir: getPulumiWorkDir(),\n });\n\n stackOutputs = await stack.outputs();\n } catch (_error: unknown) {\n progress.stop();\n clack.log.error(\"No Wraps infrastructure found\");\n console.log(\n `\\\\nRun ${pc.cyan(\"wraps email init\")} to deploy infrastructure first.\\\\n`\n );\n process.exit(1);\n }\n\n // Extract outputs from stack (optional - console uses current AWS credentials)\n const tableName = stackOutputs.tableName?.value;\n const archiveArn = stackOutputs.archiveArn?.value;\n const archivingEnabled = stackOutputs.archivingEnabled?.value ?? false;\n\n // 4. Find available port\n const port =\n options.port || (await getPort({ port: [5555, 5556, 5557, 5558, 5559] }));\n\n // 5. Start server\n progress.stop();\n clack.log.success(\"Starting dashboard server...\");\n console.log(\n `${pc.dim(\"Using current AWS credentials (no role assumption)\")}\\\\n`\n );\n\n const { url } = await startConsoleServer({\n port,\n roleArn: undefined, // Use current credentials instead of assuming role\n region,\n tableName,\n accountId: identity.accountId,\n noOpen: options.noOpen ?? false,\n archiveArn,\n archivingEnabled,\n });\n\n console.log(`\\\\n${pc.bold(\"Dashboard:\")} ${pc.cyan(url)}`);\n console.log(`${pc.dim(\"Press Ctrl+C to stop\")}\\\\n`);\n\n // 6. Open browser (unless --no-open)\n if (!options.noOpen) {\n await open(url);\n }\n\n // 7. Track console launch\n trackCommand(\"console\", {\n success: true,\n port,\n no_open: options.noOpen ?? false,\n });\n\n // Keep process alive\n await new Promise(() => {});\n}\n","import crypto from \"node:crypto\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport express from \"express\";\nimport { createHttpTerminator } from \"http-terminator\";\nimport { authenticateToken } from \"./middleware/auth.js\";\nimport { errorHandler } from \"./middleware/error.js\";\nimport { createDomainsRouter } from \"./routes/domains.js\";\nimport { createEmailsRouter } from \"./routes/emails.js\";\nimport { createMetricsRouter } from \"./routes/metrics.js\";\nimport { createSettingsRouter } from \"./routes/settings.js\";\nimport { createUserRouter } from \"./routes/user.js\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport type ServerConfig = {\n port: number;\n roleArn: string | undefined;\n region: string;\n tableName?: string;\n accountId?: string;\n noOpen: boolean;\n archiveArn?: string;\n archivingEnabled?: boolean;\n};\n\nexport type ServerInfo = {\n url: string;\n token: string;\n};\n\n/**\n * Start console server\n */\nexport async function startConsoleServer(\n config: ServerConfig\n): Promise<ServerInfo> {\n const app = express();\n\n // Generate auth token\n const authToken = crypto.randomBytes(32).toString(\"hex\");\n\n // Middleware\n app.use(express.json());\n\n // Simple rate limiting for static file requests (defense-in-depth)\n // Note: This is a localhost-only dev server with token auth, so this is just\n // a safeguard against accidental abuse or runaway scripts\n const requestCounts = new Map<string, { count: number; resetTime: number }>();\n const RATE_LIMIT_WINDOW = 60 * 1000; // 1 minute\n const RATE_LIMIT_MAX_REQUESTS = 1000; // 1000 requests per minute per IP\n\n app.use((req, res, next) => {\n const ip = req.ip || req.socket.remoteAddress || \"unknown\";\n const now = Date.now();\n const record = requestCounts.get(ip);\n\n if (!record || now > record.resetTime) {\n // New window\n requestCounts.set(ip, { count: 1, resetTime: now + RATE_LIMIT_WINDOW });\n next();\n } else if (record.count < RATE_LIMIT_MAX_REQUESTS) {\n // Within limit\n record.count++;\n next();\n } else {\n // Rate limit exceeded\n res.status(429).json({\n error: \"Too many requests, please slow down\",\n retryAfter: Math.ceil((record.resetTime - now) / 1000),\n });\n }\n });\n\n // Security headers\n app.use((_req, res, next) => {\n res.setHeader(\"X-Frame-Options\", \"DENY\");\n res.setHeader(\"X-Content-Type-Options\", \"nosniff\");\n res.setHeader(\n \"Content-Security-Policy\",\n \"default-src 'self' 'unsafe-inline' 'unsafe-eval'; \" +\n \"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; \" +\n \"font-src 'self' https://fonts.gstatic.com; \" +\n \"connect-src 'self'\"\n );\n next();\n });\n\n // Request logging middleware\n app.use((req, _res, next) => {\n console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);\n next();\n });\n\n // API routes (with authentication)\n app.use(\n \"/api/metrics\",\n authenticateToken(authToken),\n createMetricsRouter(config)\n );\n app.use(\n \"/api/domains\",\n authenticateToken(authToken),\n createDomainsRouter(config)\n );\n app.use(\n \"/api/emails\",\n authenticateToken(authToken),\n createEmailsRouter(config)\n );\n app.use(\n \"/api/settings\",\n authenticateToken(authToken),\n createSettingsRouter(config)\n );\n app.use(\"/api/user\", authenticateToken(authToken), createUserRouter(config));\n\n // Serve static files from console-ui build\n // __dirname will be dist/ after compilation, console UI is in dist/console/\n const staticDir = path.join(__dirname, \"console\");\n app.use(express.static(staticDir));\n\n // SPA fallback\n app.get(\"*\", (_req, res) => {\n res.sendFile(path.join(staticDir, \"index.html\"));\n });\n\n // Error handler\n app.use(errorHandler);\n\n // Start server\n const server = app.listen(config.port, \"127.0.0.1\");\n\n // Setup graceful shutdown\n const httpTerminator = createHttpTerminator({ server });\n\n process.on(\"SIGTERM\", async () => {\n console.log(\"\\\\nShutting down gracefully...\");\n await httpTerminator.terminate();\n process.exit(0);\n });\n\n process.on(\"SIGINT\", async () => {\n console.log(\"\\\\nShutting down gracefully...\");\n await httpTerminator.terminate();\n process.exit(0);\n });\n\n const url = `http://localhost:${config.port}?token=${authToken}`;\n\n return { url, token: authToken };\n}\n","import type { NextFunction, Request, Response } from \"express\";\n\n/**\n * Token-based authentication middleware\n */\nexport function authenticateToken(expectedToken: string) {\n return (req: Request, res: Response, next: NextFunction) => {\n // Get token from query param or header\n const token = req.query.token || req.headers[\"x-auth-token\"];\n\n if (!token || token !== expectedToken) {\n return res.status(401).json({ error: \"Unauthorized\" });\n }\n\n next();\n };\n}\n","import type { NextFunction, Request, Response } from \"express\";\n\n/**\n * Error handling middleware\n */\nexport function errorHandler(\n err: Error,\n _req: Request,\n res: Response,\n _next: NextFunction\n) {\n console.error(\"Server error:\", err);\n\n res.status(500).json({\n error: \"Internal server error\",\n message: err.message,\n });\n}\n","import type { Request, Response, Router } from \"express\";\nimport { Router as createRouter } from \"express\";\nimport type { ServerConfig } from \"../server.js\";\nimport { fetchDomainInfo } from \"../services/ses-service.js\";\n\nexport function createDomainsRouter(config: ServerConfig): Router {\n const router = createRouter();\n\n /**\n * Get domain verification status\n */\n router.get(\"/:domain\", async (req: Request, res: Response) => {\n try {\n const { domain } = req.params;\n\n if (!domain) {\n return res.status(400).json({ error: \"Domain parameter required\" });\n }\n\n const domainInfo = await fetchDomainInfo(\n config.roleArn,\n config.region,\n domain\n );\n\n res.json(domainInfo);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n res.status(500).json({ error: errorMessage });\n }\n });\n\n return router;\n}\n","import { GetSendQuotaCommand, SESClient } from \"@aws-sdk/client-ses\";\nimport { GetEmailIdentityCommand, SESv2Client } from \"@aws-sdk/client-sesv2\";\nimport { assumeRole } from \"../../utils/shared/assume-role.js\";\n\nexport type SendQuota = {\n max24HourSend: number;\n maxSendRate: number;\n sentLast24Hours: number;\n};\n\nexport type DomainInfo = {\n domain: string;\n verified: boolean;\n dkimStatus: string;\n dkimTokens: string[];\n};\n\n/**\n * Fetch SES send quota\n */\nexport async function fetchSendQuota(\n roleArn: string | undefined,\n region: string\n): Promise<SendQuota> {\n // For console usage, use current credentials instead of assuming role\n const credentials = roleArn ? await assumeRole(roleArn, region) : undefined;\n const ses = new SESClient({ region, credentials });\n\n const response = await ses.send(new GetSendQuotaCommand({}));\n\n return {\n max24HourSend: response.Max24HourSend || 0,\n maxSendRate: response.MaxSendRate || 0,\n sentLast24Hours: response.SentLast24Hours || 0,\n };\n}\n\n/**\n * Fetch domain verification status\n */\nexport async function fetchDomainInfo(\n roleArn: string | undefined,\n region: string,\n domain: string\n): Promise<DomainInfo> {\n // For console usage, use current credentials instead of assuming role\n const credentials = roleArn ? await assumeRole(roleArn, region) : undefined;\n const sesv2 = new SESv2Client({ region, credentials });\n\n const response = await sesv2.send(\n new GetEmailIdentityCommand({\n EmailIdentity: domain,\n })\n );\n\n return {\n domain,\n verified: response.VerifiedForSendingStatus ?? false,\n dkimStatus: response.DkimAttributes?.Status || \"PENDING\",\n dkimTokens: response.DkimAttributes?.Tokens || [],\n };\n}\n","import type { Request, Response, Router } from \"express\";\nimport { Router as createRouter } from \"express\";\nimport type { ServerConfig } from \"../server.js\";\nimport { fetchEmailById, fetchEmailLogs } from \"../services/email-logs.js\";\n\nexport function createEmailsRouter(config: ServerConfig): Router {\n const router = createRouter();\n\n /**\n * Get email logs\n */\n router.get(\"/\", async (req: Request, res: Response) => {\n try {\n console.log(\"Email logs request received\");\n console.log(\"Query params:\", req.query);\n console.log(\"Config:\", {\n tableName: config.tableName,\n region: config.region,\n accountId: config.accountId,\n });\n\n // Parse query parameters\n const limit = req.query.limit\n ? Number.parseInt(req.query.limit as string, 10)\n : 100;\n const startTime = req.query.startTime\n ? Number.parseInt(req.query.startTime as string, 10)\n : undefined;\n const endTime = req.query.endTime\n ? Number.parseInt(req.query.endTime as string, 10)\n : undefined;\n\n if (!config.tableName) {\n console.log(\"No table name configured\");\n return res.status(400).json({\n error:\n \"Email tracking not enabled. Deploy with enhanced integration to enable email logs.\",\n });\n }\n\n console.log(\"Fetching email logs from DynamoDB...\");\n const logs = await fetchEmailLogs({\n region: config.region,\n tableName: config.tableName,\n accountId: config.accountId,\n limit,\n startTime,\n endTime,\n });\n\n console.log(`Found ${logs.length} email logs`);\n res.json({ logs });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching email logs:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Get email details by ID\n */\n router.get(\"/:id\", async (req: Request, res: Response) => {\n try {\n const { id } = req.params;\n console.log(\"Email detail request received for ID:\", id);\n console.log(\"Request headers:\", req.headers);\n console.log(\"Request query:\", req.query);\n\n if (!config.tableName) {\n console.log(\"No table name configured\");\n return res.status(400).json({\n error:\n \"Email tracking not enabled. Deploy with enhanced integration to enable email logs.\",\n });\n }\n\n console.log(\"Fetching email details from DynamoDB...\");\n const email = await fetchEmailById(id, {\n region: config.region,\n tableName: config.tableName,\n });\n\n if (!email) {\n console.log(\"Email not found for ID:\", id);\n return res.status(404).json({ error: \"Email not found\" });\n }\n\n console.log(\"Email details found:\", email.messageId);\n console.log(\"Sending response with\", email.events.length, \"events\");\n res.json(email);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching email details:\", error);\n console.error(\n \"Stack trace:\",\n error instanceof Error ? error.stack : \"N/A\"\n );\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Get archived email content by message ID\n */\n router.get(\"/:id/archive\", async (req: Request, res: Response) => {\n try {\n const { id } = req.params;\n console.log(\"Archived email request received for message ID:\", id);\n\n if (!config.archivingEnabled) {\n console.log(\"Email archiving not enabled\");\n return res.status(400).json({\n error: \"Email archiving not enabled for this deployment.\",\n });\n }\n\n if (!config.archiveArn) {\n console.log(\"No archive ARN configured\");\n return res.status(400).json({\n error: \"Archive ARN not configured.\",\n });\n }\n\n if (!config.tableName) {\n console.log(\"No table name configured\");\n return res.status(400).json({\n error:\n \"Email tracking not enabled. Need email metadata to search archive.\",\n });\n }\n\n // First, fetch email details from DynamoDB to get search metadata\n console.log(\"Fetching email metadata from DynamoDB...\");\n const emailDetails = await fetchEmailById(id, {\n region: config.region,\n tableName: config.tableName,\n });\n\n if (!emailDetails) {\n console.log(\"Email metadata not found in DynamoDB for ID:\", id);\n return res.status(404).json({\n error: \"Email metadata not found. Cannot search archive.\",\n });\n }\n\n console.log(\"Fetching archived email from Mail Manager...\");\n const { fetchArchivedEmail } = await import(\n \"../services/email-archive.js\"\n );\n const archivedEmail = await fetchArchivedEmail(id, {\n region: config.region,\n archiveArn: config.archiveArn,\n from: emailDetails.from,\n to: emailDetails.to[0], // Use first recipient for search\n subject: emailDetails.subject,\n timestamp: new Date(emailDetails.sentAt),\n });\n\n if (!archivedEmail) {\n console.log(\"Archived email not found for message ID:\", id);\n return res.status(404).json({\n error:\n \"Archived email not found. It may have been sent before archiving was enabled.\",\n });\n }\n\n console.log(\"Archived email found:\", archivedEmail.messageId);\n res.json(archivedEmail);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching archived email:\", error);\n console.error(\n \"Stack trace:\",\n error instanceof Error ? error.stack : \"N/A\"\n );\n res.status(500).json({ error: errorMessage });\n }\n });\n\n return router;\n}\n","import {\n DynamoDBClient,\n QueryCommand,\n ScanCommand,\n} from \"@aws-sdk/client-dynamodb\";\nimport { unmarshall } from \"@aws-sdk/util-dynamodb\";\n\nexport type EmailLog = {\n messageId: string;\n to: string[]; // Array of recipients\n from: string;\n subject: string;\n status:\n | \"delivered\"\n | \"bounced\"\n | \"complained\"\n | \"sent\"\n | \"failed\"\n | \"opened\"\n | \"clicked\";\n sentAt: number;\n accountId?: string;\n errorMessage?: string;\n};\n\nexport type EmailEvent = {\n type:\n | \"sent\"\n | \"delivered\"\n | \"bounced\"\n | \"complained\"\n | \"opened\"\n | \"clicked\"\n | \"failed\";\n timestamp: number;\n metadata?: Record<string, any>;\n};\n\nexport type EmailDetails = {\n id: string;\n messageId: string;\n from: string;\n to: string[];\n replyTo?: string;\n subject: string;\n htmlBody?: string;\n textBody?: string;\n status:\n | \"delivered\"\n | \"bounced\"\n | \"complained\"\n | \"sent\"\n | \"failed\"\n | \"opened\"\n | \"clicked\";\n sentAt: number;\n events: EmailEvent[];\n};\n\ntype FetchEmailLogsOptions = {\n region: string;\n tableName: string;\n accountId?: string;\n limit?: number;\n startTime?: number;\n endTime?: number;\n};\n\n/**\n * Fetch email logs from DynamoDB\n */\nexport async function fetchEmailLogs(\n options: FetchEmailLogsOptions\n): Promise<EmailLog[]> {\n const {\n region,\n tableName,\n accountId,\n limit = 100,\n startTime,\n endTime,\n } = options;\n\n const dynamodb = new DynamoDBClient({ region });\n\n try {\n // If we have accountId, use GSI for better performance\n let items: any[] = [];\n if (accountId) {\n let keyConditionExpression = \"accountId = :accountId\";\n const expressionAttributeValues: Record<string, any> = {\n \":accountId\": { S: accountId },\n };\n\n // Add time range if provided\n if (startTime && endTime) {\n keyConditionExpression += \" AND sentAt BETWEEN :startTime AND :endTime\";\n expressionAttributeValues[\":startTime\"] = { N: startTime.toString() };\n expressionAttributeValues[\":endTime\"] = { N: endTime.toString() };\n } else if (startTime) {\n keyConditionExpression += \" AND sentAt >= :startTime\";\n expressionAttributeValues[\":startTime\"] = { N: startTime.toString() };\n }\n\n const response = await dynamodb.send(\n new QueryCommand({\n TableName: tableName,\n IndexName: \"accountId-sentAt-index\",\n KeyConditionExpression: keyConditionExpression,\n ExpressionAttributeValues: expressionAttributeValues,\n ScanIndexForward: false, // Sort by sentAt descending (newest first)\n })\n );\n\n items = response.Items || [];\n } else {\n // Otherwise, scan the table (less efficient but works without accountId)\n const response = await dynamodb.send(\n new ScanCommand({\n TableName: tableName,\n })\n );\n\n items = response.Items || [];\n }\n\n // Unmarshall all items\n const unmarshalled = items.map((item) => unmarshall(item));\n\n // Group events by messageId to get the latest status for each email\n const emailMap = new Map<string, any>();\n\n for (const item of unmarshalled) {\n const messageId = item.messageId;\n const existing = emailMap.get(messageId);\n\n if (existing) {\n // Keep the event with the most important status\n // Priority: Complaint > Permanent Bounce > Delivery > Transient Bounce > Send\n const currentPriority = getEventPriority(item);\n const existingPriority = getEventPriority(existing);\n\n if (currentPriority > existingPriority) {\n emailMap.set(messageId, item);\n }\n } else {\n emailMap.set(messageId, item);\n }\n }\n\n // Convert map to array and normalize\n const logs = Array.from(emailMap.values())\n .map(normalizeEmailLog)\n .sort((a, b) => b.sentAt - a.sentAt);\n\n // Apply limit\n return logs.slice(0, limit);\n } catch (error) {\n console.error(\"Error fetching email logs:\", error);\n throw error;\n }\n}\n\n/**\n * Get priority for event type (higher = more important to display)\n * Priority: Complaint > Permanent Bounce > Click > Open > Delivery > Transient Bounce > Send\n */\nfunction getEventPriority(item: any): number {\n const type = item.eventType?.toLowerCase();\n\n switch (type) {\n case \"complaint\":\n return 7;\n case \"bounce\": {\n // Permanent bounces (hard bounces) are more important than delivery\n // Transient bounces (OOTO, mailbox full) are less important than delivery\n const bounceType = item.bounceType?.toLowerCase();\n return bounceType === \"permanent\" ? 6 : 2;\n }\n case \"click\":\n return 5;\n case \"open\":\n return 4;\n case \"delivery\":\n return 3;\n case \"send\":\n return 1;\n default:\n return 0;\n }\n}\n\n/**\n * Normalize email log data from DynamoDB\n */\nfunction normalizeEmailLog(data: any): EmailLog {\n // Determine status based on eventType\n let status: EmailLog[\"status\"] = \"sent\";\n const eventType = data.eventType?.toLowerCase();\n\n if (eventType === \"complaint\") {\n status = \"complained\";\n } else if (eventType === \"bounce\") {\n status = \"bounced\";\n } else if (eventType === \"click\") {\n status = \"clicked\";\n } else if (eventType === \"open\") {\n status = \"opened\";\n } else if (eventType === \"delivery\") {\n status = \"delivered\";\n } else if (eventType === \"send\") {\n status = \"sent\";\n } else if (data.errorMessage) {\n status = \"failed\";\n }\n\n // Handle 'to' field - it's stored as a String Set in DynamoDB\n // DynamoDB String Sets get unmarshalled as JavaScript Set objects\n let toAddresses: string[] = [];\n const toField = data.to || data.destination; // CSV export might show as 'destination'\n\n if (toField) {\n console.log(\n \"Raw 'to' field:\",\n toField,\n \"Type:\",\n typeof toField,\n \"Constructor:\",\n toField.constructor?.name\n );\n\n if (toField instanceof Set) {\n // DynamoDB String Set -> JavaScript Set\n toAddresses = Array.from(toField);\n } else if (Array.isArray(toField)) {\n toAddresses = toField;\n } else if (typeof toField === \"string\") {\n toAddresses = [toField];\n }\n }\n\n console.log(\"Normalized toAddresses:\", toAddresses);\n\n return {\n messageId: data.messageId,\n to: toAddresses,\n from: data.from || \"unknown\",\n subject: data.subject || \"(no subject)\",\n status,\n sentAt: Number(data.sentAt),\n accountId: data.accountId,\n errorMessage: data.errorMessage,\n };\n}\n\n/**\n * Fetch email details by message ID (with all events)\n */\nexport async function fetchEmailById(\n messageId: string,\n options: { region: string; tableName: string }\n): Promise<EmailDetails | null> {\n const { region, tableName } = options;\n const dynamodb = new DynamoDBClient({ region });\n\n try {\n // Query all events for this messageId\n const response = await dynamodb.send(\n new QueryCommand({\n TableName: tableName,\n KeyConditionExpression: \"messageId = :messageId\",\n ExpressionAttributeValues: {\n \":messageId\": { S: messageId },\n },\n })\n );\n\n const items = response.Items || [];\n\n if (items.length === 0) {\n return null;\n }\n\n // Unmarshall all events\n const events = items.map((item) => unmarshall(item));\n\n // Get the send event (has the email content)\n const sendEvent = events.find((e) => e.eventType?.toLowerCase() === \"send\");\n\n if (!sendEvent) {\n return null;\n }\n\n console.log(\"Send event fields:\", {\n from: sendEvent.from,\n source: sendEvent.source,\n subject: sendEvent.subject,\n to: sendEvent.to,\n destination: sendEvent.destination,\n availableKeys: Object.keys(sendEvent),\n });\n\n // Try to extract email content from eventData\n let htmlBody: string | undefined;\n let textBody: string | undefined;\n\n if (sendEvent.eventData) {\n try {\n const eventData = JSON.parse(sendEvent.eventData);\n console.log(\"Send event data keys:\", Object.keys(eventData));\n\n // SES doesn't include email content in events by default\n // Check if content was somehow included\n if (eventData.content) {\n htmlBody = eventData.content.html;\n textBody = eventData.content.text;\n }\n\n // Check mail.content (unlikely but worth trying)\n if (eventData.mail?.content) {\n htmlBody = eventData.mail.content.html;\n textBody = eventData.mail.content.text;\n }\n } catch (e) {\n console.error(\"Failed to parse eventData:\", e);\n }\n }\n\n // Parse to addresses\n let toAddresses: string[] = [];\n const toField = sendEvent.to || sendEvent.destination;\n\n if (toField) {\n if (toField instanceof Set) {\n toAddresses = Array.from(toField);\n } else if (Array.isArray(toField)) {\n toAddresses = toField;\n } else if (typeof toField === \"string\") {\n toAddresses = [toField];\n }\n }\n\n // Determine final status (priority order: complaint > bounce > click > open > delivery > sent)\n let status: EmailDetails[\"status\"] = \"sent\";\n const hasDelivery = events.some(\n (e) => e.eventType?.toLowerCase() === \"delivery\"\n );\n const hasBounce = events.some(\n (e) => e.eventType?.toLowerCase() === \"bounce\"\n );\n const hasComplaint = events.some(\n (e) => e.eventType?.toLowerCase() === \"complaint\"\n );\n const hasOpen = events.some((e) => e.eventType?.toLowerCase() === \"open\");\n const hasClick = events.some((e) => e.eventType?.toLowerCase() === \"click\");\n\n if (hasComplaint) {\n status = \"complained\";\n } else if (hasBounce) {\n status = \"bounced\";\n } else if (hasClick) {\n status = \"clicked\";\n } else if (hasOpen) {\n status = \"opened\";\n } else if (hasDelivery) {\n status = \"delivered\";\n }\n\n // Map events to simplified timeline\n const timeline: EmailEvent[] = events\n .map((event) => {\n const eventType = event.eventType?.toLowerCase();\n let type: EmailEvent[\"type\"] = \"sent\";\n\n switch (eventType) {\n case \"send\":\n type = \"sent\";\n break;\n case \"delivery\":\n type = \"delivered\";\n break;\n case \"bounce\":\n type = \"bounced\";\n break;\n case \"complaint\":\n type = \"complained\";\n break;\n case \"open\":\n type = \"opened\";\n break;\n case \"click\":\n type = \"clicked\";\n break;\n default:\n type = \"sent\";\n }\n\n const metadata: Record<string, any> = {};\n\n // Add relevant metadata based on event type\n if (eventType === \"bounce\" && event.bounceType) {\n metadata.bounceType = event.bounceType;\n metadata.bounceSubType = event.bounceSubType;\n }\n\n if (eventType === \"complaint\" && event.complaintFeedbackType) {\n metadata.feedbackType = event.complaintFeedbackType;\n }\n\n if (eventType === \"click\" && event.link) {\n metadata.link = event.link;\n }\n\n if (event.userAgent) {\n metadata.userAgent = event.userAgent;\n }\n\n return {\n type,\n timestamp: Number(event.sentAt || event.timestamp),\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n };\n })\n .sort((a, b) => a.timestamp - b.timestamp);\n\n return {\n id: messageId,\n messageId,\n from: sendEvent.from || \"unknown\",\n to: toAddresses,\n replyTo: sendEvent.replyTo,\n subject: sendEvent.subject || \"(no subject)\",\n htmlBody: htmlBody || sendEvent.htmlBody,\n textBody: textBody || sendEvent.textBody,\n status,\n sentAt: Number(sendEvent.sentAt),\n events: timeline,\n };\n } catch (error) {\n console.error(\"Error fetching email by ID:\", error);\n throw error;\n }\n}\n","import type { Request, Response, Router } from \"express\";\nimport { Router as createRouter } from \"express\";\nimport type { ServerConfig } from \"../server.js\";\nimport { fetchSESMetrics } from \"../services/aws-metrics.js\";\nimport { fetchSendQuota } from \"../services/ses-service.js\";\n\nexport function createMetricsRouter(config: ServerConfig): Router {\n const router = createRouter();\n\n /**\n * SSE endpoint for real-time metrics\n */\n router.get(\"/stream\", async (req: Request, res: Response) => {\n // Set SSE headers\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n // Send initial connection event\n res.write('data: {\"type\":\"connected\"}\\n\\n');\n\n // Get time range from query params, default to last 24 hours\n const { startTime, endTime } = req.query;\n const getTimeRange = () => ({\n start: startTime\n ? new Date(Number.parseInt(startTime as string, 10))\n : new Date(Date.now() - 24 * 60 * 60 * 1000),\n end: endTime\n ? new Date(Number.parseInt(endTime as string, 10))\n : new Date(),\n });\n\n // Function to fetch and send metrics\n const sendMetrics = async () => {\n try {\n console.log(\"Fetching metrics from AWS...\");\n\n const timeRange = getTimeRange();\n\n console.log(\"Time range:\", timeRange);\n console.log(\"Config:\", {\n region: config.region,\n roleArn: config.roleArn\n ? `${config.roleArn.substring(0, 30)}...`\n : \"using current credentials\",\n });\n\n const [metrics, quota] = await Promise.all([\n fetchSESMetrics(\n config.roleArn,\n config.region,\n timeRange,\n config.tableName\n ),\n fetchSendQuota(config.roleArn, config.region),\n ]);\n\n console.log(\"Metrics fetched successfully\");\n\n const data = {\n type: \"metrics\",\n timestamp: Date.now(),\n metrics,\n quota,\n };\n\n res.write(`data: ${JSON.stringify(data)}\\n\\n`);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching metrics:\", error);\n res.write(\n `data: ${JSON.stringify({ type: \"error\", error: errorMessage })}\\n\\n`\n );\n }\n };\n\n // Send immediately on connect\n await sendMetrics();\n\n // Poll every 60 seconds\n const interval = setInterval(sendMetrics, 60_000);\n\n // Clean up on disconnect\n req.on(\"close\", () => {\n clearInterval(interval);\n });\n });\n\n /**\n * Get current metrics snapshot (REST endpoint)\n */\n router.get(\"/snapshot\", async (_req: Request, res: Response) => {\n try {\n const timeRange = {\n start: new Date(Date.now() - 24 * 60 * 60 * 1000),\n end: new Date(),\n };\n\n const [metrics, quota] = await Promise.all([\n fetchSESMetrics(\n config.roleArn,\n config.region,\n timeRange,\n config.tableName\n ),\n fetchSendQuota(config.roleArn, config.region),\n ]);\n\n res.json({ metrics, quota });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Get metrics for a specific time range\n */\n router.get(\"/\", async (req: Request, res: Response) => {\n try {\n const { startTime, endTime } = req.query;\n\n // Default to last 24 hours if no time range provided\n const timeRange = {\n start: startTime\n ? new Date(Number.parseInt(startTime as string, 10))\n : new Date(Date.now() - 24 * 60 * 60 * 1000),\n end: endTime\n ? new Date(Number.parseInt(endTime as string, 10))\n : new Date(),\n };\n\n const [metrics, quota] = await Promise.all([\n fetchSESMetrics(\n config.roleArn,\n config.region,\n timeRange,\n config.tableName\n ),\n fetchSendQuota(config.roleArn, config.region),\n ]);\n\n res.json({\n metrics,\n quota,\n timestamp: Date.now(),\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching metrics:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n return router;\n}\n","import {\n CloudWatchClient,\n GetMetricDataCommand,\n type MetricDataQuery,\n} from \"@aws-sdk/client-cloudwatch\";\nimport { assumeRole } from \"../../utils/shared/assume-role.js\";\n\nexport type MetricsData = {\n sends: Array<{ timestamp: number; value: number }>;\n bounces: Array<{ timestamp: number; value: number }>;\n complaints: Array<{ timestamp: number; value: number }>;\n deliveries: Array<{ timestamp: number; value: number }>;\n opens: Array<{ timestamp: number; value: number }>;\n clicks: Array<{ timestamp: number; value: number }>;\n};\n\n/**\n * Fetch SES metrics from CloudWatch\n */\nexport async function fetchSESMetrics(\n roleArn: string | undefined,\n region: string,\n timeRange: { start: Date; end: Date },\n tableName?: string\n): Promise<MetricsData> {\n // For console usage, use current credentials instead of assuming role\n const credentials = roleArn ? await assumeRole(roleArn, region) : undefined;\n\n // Create CloudWatch client\n const cloudwatch = new CloudWatchClient({ region, credentials });\n\n // Define metric queries\n const queries: MetricDataQuery[] = [\n {\n Id: \"sends\",\n MetricStat: {\n Metric: {\n Namespace: \"AWS/SES\",\n MetricName: \"Send\",\n },\n Period: 300, // 5 minutes\n Stat: \"Sum\",\n },\n },\n {\n Id: \"bounces\",\n MetricStat: {\n Metric: {\n Namespace: \"AWS/SES\",\n MetricName: \"Bounce\",\n },\n Period: 300,\n Stat: \"Sum\",\n },\n },\n {\n Id: \"complaints\",\n MetricStat: {\n Metric: {\n Namespace: \"AWS/SES\",\n MetricName: \"Complaint\",\n },\n Period: 300,\n Stat: \"Sum\",\n },\n },\n {\n Id: \"deliveries\",\n MetricStat: {\n Metric: {\n Namespace: \"AWS/SES\",\n MetricName: \"Delivery\",\n },\n Period: 300,\n Stat: \"Sum\",\n },\n },\n ];\n\n // Fetch metrics\n const response = await cloudwatch.send(\n new GetMetricDataCommand({\n MetricDataQueries: queries,\n StartTime: timeRange.start,\n EndTime: timeRange.end,\n })\n );\n\n // Parse results\n const results = response.MetricDataResults || [];\n\n const parseMetric = (id: string) => {\n const metric = results.find((r) => r.Id === id);\n if (!(metric?.Timestamps && metric.Values)) {\n return [];\n }\n\n return metric.Timestamps.map((timestamp, i) => ({\n timestamp: timestamp.getTime(),\n value: metric.Values?.[i] || 0,\n }));\n };\n\n // Fetch Opens and Clicks from DynamoDB if table name is provided\n let opens: Array<{ timestamp: number; value: number }> = [];\n let clicks: Array<{ timestamp: number; value: number }> = [];\n\n if (tableName) {\n try {\n const { fetchDynamoDBMetrics } = await import(\"./dynamodb-metrics.js\");\n const dynamoMetrics = await fetchDynamoDBMetrics(\n region,\n tableName,\n timeRange\n );\n opens = dynamoMetrics.opens;\n clicks = dynamoMetrics.clicks;\n } catch (error) {\n console.error(\"Error fetching DynamoDB metrics:\", error);\n // Continue with empty arrays\n }\n }\n\n return {\n sends: parseMetric(\"sends\"),\n bounces: parseMetric(\"bounces\"),\n complaints: parseMetric(\"complaints\"),\n deliveries: parseMetric(\"deliveries\"),\n opens,\n clicks,\n };\n}\n","import dns from \"node:dns/promises\";\nimport type { Request, Response, Router } from \"express\";\nimport { Router as createRouter } from \"express\";\nimport { loadConnectionMetadata } from \"../../utils/shared/metadata.js\";\nimport type { ServerConfig } from \"../server.js\";\nimport { fetchEmailSettings } from \"../services/settings-service.js\";\n\nexport function createSettingsRouter(config: ServerConfig): Router {\n const router = createRouter();\n\n /**\n * Get deployment configuration\n */\n router.get(\"/deployment\", async (_req: Request, res: Response) => {\n try {\n res.json({\n archivingEnabled: config.archivingEnabled ?? false,\n archiveArn: config.archiveArn,\n tableName: config.tableName,\n region: config.region,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching deployment config:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Get email settings (configuration set + identity)\n */\n router.get(\"/\", async (_req: Request, res: Response) => {\n try {\n // Load metadata to get configuration\n const metadata = await loadConnectionMetadata(\n config.accountId || \"\",\n config.region\n );\n\n if (!metadata) {\n return res.status(404).json({\n error: \"No Wraps infrastructure found for this account and region\",\n });\n }\n\n // Get configuration set name and domain from metadata\n const configSetName = \"wraps-email-tracking\"; // Always use this name\n const domain = metadata.services.email?.config.domain;\n\n // Fetch settings from AWS\n const settings = await fetchEmailSettings(\n config.roleArn,\n config.region,\n configSetName,\n domain\n );\n\n // Add region to response\n res.json({\n ...settings,\n region: config.region,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching settings:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Verify tracking domain CNAME\n */\n router.get(\"/verify-tracking-domain\", async (req: Request, res: Response) => {\n try {\n const { domain, expectedTarget } = req.query;\n\n if (!domain || typeof domain !== \"string\") {\n return res.status(400).json({ error: \"Domain parameter required\" });\n }\n\n if (!expectedTarget || typeof expectedTarget !== \"string\") {\n return res\n .status(400)\n .json({ error: \"Expected target parameter required\" });\n }\n\n console.log(`[Verify] Checking CNAME for: ${domain}`);\n console.log(`[Verify] Expected target: ${expectedTarget}`);\n\n // Check CNAME record using DNS\n const records = await dns.resolveCname(domain);\n\n console.log(\"[Verify] CNAME records found:\", records);\n\n // Check if any CNAME points to the expected target\n const verified = records.some((record) =>\n record.toLowerCase().includes(expectedTarget.toLowerCase())\n );\n\n console.log(`[Verify] Verified: ${verified}`);\n\n res.json({\n verified,\n error: verified\n ? undefined\n : `CNAME not pointing to ${expectedTarget}. Found: ${records.join(\", \")}`,\n });\n } catch (error: any) {\n console.error(\"[Verify] Error verifying tracking domain:\", error);\n\n // If no CNAME record exists, DNS will throw ENODATA or ENOTFOUND\n if (error.code === \"ENODATA\" || error.code === \"ENOTFOUND\") {\n return res.json({\n verified: false,\n error: \"No CNAME record found for this domain\",\n });\n }\n\n const errorMessage =\n error instanceof Error ? error.message : \"Failed to verify\";\n res.json({\n verified: false,\n error: errorMessage,\n });\n }\n });\n\n /**\n * Verify DMARC TXT record\n */\n router.get(\"/verify-dmarc\", async (req: Request, res: Response) => {\n try {\n const { domain } = req.query;\n\n if (!domain || typeof domain !== \"string\") {\n return res.status(400).json({ error: \"Domain parameter required\" });\n }\n\n const dmarcDomain = `_dmarc.${domain}`;\n\n console.log(`[Verify] Checking DMARC for: ${dmarcDomain}`);\n\n // Use Node.js DNS to resolve TXT records\n const records = await dns.resolveTxt(dmarcDomain);\n\n console.log(\"[Verify] TXT records found:\", records);\n\n // Check if there's a TXT record that starts with \"v=DMARC1\"\n // TXT records are arrays of strings, so we need to join them\n const hasDmarc = records.some((record) => {\n const value = record.join(\"\");\n return value.startsWith(\"v=DMARC1\");\n });\n\n console.log(`[Verify] DMARC verified: ${hasDmarc}`);\n\n res.json({\n verified: hasDmarc,\n error: hasDmarc ? undefined : \"DMARC record not found\",\n });\n } catch (error: any) {\n console.error(\"[Verify] Error verifying DMARC:\", error);\n\n // If no TXT record exists, DNS will throw ENODATA or ENOTFOUND\n if (error.code === \"ENODATA\" || error.code === \"ENOTFOUND\") {\n return res.json({\n verified: false,\n error: \"No DMARC record found for this domain\",\n });\n }\n\n const errorMessage =\n error instanceof Error ? error.message : \"Failed to verify\";\n res.json({\n verified: false,\n error: errorMessage,\n });\n }\n });\n\n /**\n * Update configuration set sending options\n */\n router.put(\"/config-set/sending\", async (req: Request, res: Response) => {\n try {\n const { enabled } = req.body;\n\n if (typeof enabled !== \"boolean\") {\n return res.status(400).json({ error: \"enabled must be a boolean\" });\n }\n\n // Load metadata to get configuration set name\n const metadata = await loadConnectionMetadata(\n config.accountId || \"\",\n config.region\n );\n\n if (!metadata) {\n return res.status(404).json({\n error: \"No Wraps infrastructure found for this account and region\",\n });\n }\n\n const configSetName = \"wraps-email-tracking\";\n\n console.log(\n `[Settings] Updating sending options for ${configSetName}: ${enabled}`\n );\n\n // Update sending options via AWS SDK\n const { SESv2Client, PutConfigurationSetSendingOptionsCommand } =\n await import(\"@aws-sdk/client-sesv2\");\n const { assumeRole } = await import(\"../../utils/shared/assume-role.js\");\n\n const credentials = config.roleArn\n ? await assumeRole(config.roleArn, config.region)\n : undefined;\n const sesClient = new SESv2Client({ region: config.region, credentials });\n\n await sesClient.send(\n new PutConfigurationSetSendingOptionsCommand({\n ConfigurationSetName: configSetName,\n SendingEnabled: enabled,\n })\n );\n\n console.log(\"[Settings] Successfully updated sending options\");\n\n res.json({ success: true });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"[Settings] Error updating sending options:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Update configuration set reputation options\n */\n router.put(\"/config-set/reputation\", async (req: Request, res: Response) => {\n try {\n const { enabled } = req.body;\n\n if (typeof enabled !== \"boolean\") {\n return res.status(400).json({ error: \"enabled must be a boolean\" });\n }\n\n // Load metadata to get configuration set name\n const metadata = await loadConnectionMetadata(\n config.accountId || \"\",\n config.region\n );\n\n if (!metadata) {\n return res.status(404).json({\n error: \"No Wraps infrastructure found for this account and region\",\n });\n }\n\n const configSetName = \"wraps-email-tracking\";\n\n console.log(\n `[Settings] Updating reputation options for ${configSetName}: ${enabled}`\n );\n\n // Update reputation options via AWS SDK\n const { SESv2Client, PutConfigurationSetReputationOptionsCommand } =\n await import(\"@aws-sdk/client-sesv2\");\n const { assumeRole } = await import(\"../../utils/shared/assume-role.js\");\n\n const credentials = config.roleArn\n ? await assumeRole(config.roleArn, config.region)\n : undefined;\n const sesClient = new SESv2Client({ region: config.region, credentials });\n\n await sesClient.send(\n new PutConfigurationSetReputationOptionsCommand({\n ConfigurationSetName: configSetName,\n ReputationMetricsEnabled: enabled,\n })\n );\n\n console.log(\"[Settings] Successfully updated reputation options\");\n\n res.json({ success: true });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"[Settings] Error updating reputation options:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Update tracking domain\n */\n router.put(\n \"/config-set/tracking-domain\",\n async (req: Request, res: Response) => {\n try {\n const { domain } = req.body;\n\n if (!domain || typeof domain !== \"string\") {\n return res.status(400).json({ error: \"domain must be a string\" });\n }\n\n // Validate domain format (basic check)\n const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-_.]+[a-zA-Z0-9]$/;\n if (!domainRegex.test(domain)) {\n return res.status(400).json({ error: \"Invalid domain format\" });\n }\n\n // Load metadata to get configuration set name\n const metadata = await loadConnectionMetadata(\n config.accountId || \"\",\n config.region\n );\n\n if (!metadata) {\n return res.status(404).json({\n error: \"No Wraps infrastructure found for this account and region\",\n });\n }\n\n const configSetName = \"wraps-email-tracking\";\n\n console.log(\n `[Settings] Updating tracking domain for ${configSetName}: ${domain}`\n );\n\n // Update tracking options via AWS SDK\n const { SESv2Client, PutConfigurationSetTrackingOptionsCommand } =\n await import(\"@aws-sdk/client-sesv2\");\n const { assumeRole } = await import(\n \"../../utils/shared/assume-role.js\"\n );\n\n const credentials = config.roleArn\n ? await assumeRole(config.roleArn, config.region)\n : undefined;\n const sesClient = new SESv2Client({\n region: config.region,\n credentials,\n });\n\n await sesClient.send(\n new PutConfigurationSetTrackingOptionsCommand({\n ConfigurationSetName: configSetName,\n CustomRedirectDomain: domain,\n })\n );\n\n console.log(\"[Settings] Successfully updated tracking domain\");\n\n res.json({ success: true });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"[Settings] Error updating tracking domain:\", error);\n res.status(500).json({ error: errorMessage });\n }\n }\n );\n\n return router;\n}\n","import {\n GetConfigurationSetCommand,\n GetEmailIdentityCommand,\n SESv2Client,\n} from \"@aws-sdk/client-sesv2\";\nimport { assumeRole } from \"../../utils/shared/assume-role.js\";\n\nexport type EmailSettings = {\n configurationSet?: ConfigurationSetDetails;\n identity?: EmailIdentityDetails;\n};\n\nexport type ConfigurationSetDetails = {\n name: string;\n trackingOptions?: {\n customRedirectDomain?: string;\n httpsPolicy?: \"REQUIRE\" | \"OPTIONAL\";\n };\n deliveryOptions?: {\n tlsPolicy?: \"REQUIRE\" | \"OPTIONAL\";\n sendingPoolName?: string;\n };\n reputationOptions?: {\n reputationMetricsEnabled: boolean;\n lastFreshStart?: Date;\n };\n sendingOptions?: {\n sendingEnabled: boolean;\n };\n suppressionOptions?: {\n suppressedReasons?: (\"BOUNCE\" | \"COMPLAINT\")[];\n };\n};\n\nexport type EmailIdentityDetails = {\n identityType: \"EMAIL_ADDRESS\" | \"DOMAIN\";\n identityName: string;\n verificationStatus:\n | \"PENDING\"\n | \"SUCCESS\"\n | \"FAILED\"\n | \"TEMPORARY_FAILURE\"\n | \"NOT_STARTED\";\n dkimAttributes?: {\n status: \"SUCCESS\" | \"PENDING\" | \"FAILED\" | \"NOT_STARTED\";\n tokens?: string[];\n signingEnabled: boolean;\n signingKeyLength?: \"RSA_1024_BIT\" | \"RSA_2048_BIT\";\n };\n mailFromAttributes?: {\n mailFromDomain?: string;\n mailFromDomainStatus?: \"PENDING\" | \"SUCCESS\" | \"FAILED\";\n behaviorOnMxFailure?: \"USE_DEFAULT_VALUE\" | \"REJECT_MESSAGE\";\n };\n configurationSetName?: string;\n verifiedForSendingStatus: boolean;\n tags?: Record<string, string>;\n};\n\n/**\n * Fetch configuration set details\n */\nexport async function fetchConfigurationSet(\n roleArn: string | undefined,\n region: string,\n configSetName: string\n): Promise<ConfigurationSetDetails> {\n const credentials = roleArn ? await assumeRole(roleArn, region) : undefined;\n const sesv2 = new SESv2Client({ region, credentials });\n\n const response = await sesv2.send(\n new GetConfigurationSetCommand({\n ConfigurationSetName: configSetName,\n })\n );\n\n return {\n name: configSetName,\n trackingOptions: response.TrackingOptions\n ? {\n customRedirectDomain: response.TrackingOptions.CustomRedirectDomain,\n httpsPolicy: response.TrackingOptions.HttpsPolicy as\n | \"REQUIRE\"\n | \"OPTIONAL\",\n }\n : undefined,\n deliveryOptions: response.DeliveryOptions\n ? {\n tlsPolicy: response.DeliveryOptions.TlsPolicy as\n | \"REQUIRE\"\n | \"OPTIONAL\",\n sendingPoolName: response.DeliveryOptions.SendingPoolName,\n }\n : undefined,\n reputationOptions: response.ReputationOptions\n ? {\n reputationMetricsEnabled:\n response.ReputationOptions.ReputationMetricsEnabled ?? false,\n lastFreshStart: response.ReputationOptions.LastFreshStart,\n }\n : undefined,\n sendingOptions: response.SendingOptions\n ? {\n sendingEnabled: response.SendingOptions.SendingEnabled ?? true,\n }\n : undefined,\n suppressionOptions: response.SuppressionOptions\n ? {\n suppressedReasons: response.SuppressionOptions.SuppressedReasons as\n | (\"BOUNCE\" | \"COMPLAINT\")[]\n | undefined,\n }\n : undefined,\n };\n}\n\n/**\n * Fetch email identity details\n */\nexport async function fetchEmailIdentity(\n roleArn: string | undefined,\n region: string,\n identityName: string\n): Promise<EmailIdentityDetails> {\n const credentials = roleArn ? await assumeRole(roleArn, region) : undefined;\n const sesv2 = new SESv2Client({ region, credentials });\n\n const response = await sesv2.send(\n new GetEmailIdentityCommand({\n EmailIdentity: identityName,\n })\n );\n\n return {\n identityType: response.IdentityType as \"EMAIL_ADDRESS\" | \"DOMAIN\",\n identityName,\n verificationStatus:\n response.VerificationStatus as EmailIdentityDetails[\"verificationStatus\"],\n dkimAttributes: response.DkimAttributes\n ? {\n status: response.DkimAttributes.Status as\n | \"SUCCESS\"\n | \"PENDING\"\n | \"FAILED\"\n | \"NOT_STARTED\",\n tokens: response.DkimAttributes.Tokens,\n signingEnabled: response.DkimAttributes.SigningEnabled ?? false,\n signingKeyLength: response.DkimAttributes\n .NextSigningKeyLength as NonNullable<\n EmailIdentityDetails[\"dkimAttributes\"]\n >[\"signingKeyLength\"],\n }\n : undefined,\n mailFromAttributes: response.MailFromAttributes\n ? {\n mailFromDomain: response.MailFromAttributes.MailFromDomain,\n mailFromDomainStatus: response.MailFromAttributes\n .MailFromDomainStatus as NonNullable<\n EmailIdentityDetails[\"mailFromAttributes\"]\n >[\"mailFromDomainStatus\"],\n behaviorOnMxFailure: response.MailFromAttributes\n .BehaviorOnMxFailure as NonNullable<\n EmailIdentityDetails[\"mailFromAttributes\"]\n >[\"behaviorOnMxFailure\"],\n }\n : undefined,\n configurationSetName: response.ConfigurationSetName,\n verifiedForSendingStatus: response.VerifiedForSendingStatus ?? false,\n tags: response.Tags?.reduce(\n (acc, tag) => {\n if (tag.Key) {\n acc[tag.Key] = tag.Value || \"\";\n }\n return acc;\n },\n {} as Record<string, string>\n ),\n };\n}\n\n/**\n * Fetch complete email settings\n */\nexport async function fetchEmailSettings(\n roleArn: string | undefined,\n region: string,\n configSetName?: string,\n domain?: string\n): Promise<EmailSettings> {\n const settings: EmailSettings = {};\n\n if (configSetName) {\n try {\n settings.configurationSet = await fetchConfigurationSet(\n roleArn,\n region,\n configSetName\n );\n } catch (error) {\n console.error(\"Failed to fetch configuration set:\", error);\n }\n }\n\n if (domain) {\n try {\n settings.identity = await fetchEmailIdentity(roleArn, region, domain);\n } catch (error) {\n console.error(\"Failed to fetch email identity:\", error);\n }\n }\n\n return settings;\n}\n","import type { Request, Response, Router } from \"express\";\nimport { Router as createRouter } from \"express\";\nimport { loadConnectionMetadata } from \"../../utils/shared/metadata.js\";\nimport type { ServerConfig } from \"../server.js\";\n\nexport function createUserRouter(config: ServerConfig): Router {\n const router = createRouter();\n\n /**\n * Get current AWS user/account information\n */\n router.get(\"/\", async (_req: Request, res: Response) => {\n try {\n const accountId = config.accountId || \"Unknown\";\n const region = config.region;\n\n console.log(\n \"[User API] Fetching user info for account:\",\n accountId,\n \"region:\",\n region\n );\n\n // Load metadata to get additional details\n const metadata = await loadConnectionMetadata(accountId, region);\n console.log(\n \"[User API] Metadata loaded:\",\n metadata ? \"found\" : \"not found\"\n );\n\n // Get AWS account alias if available (for better UX)\n let accountAlias = accountId;\n try {\n if (config.roleArn) {\n console.log(\"[User API] Attempting to fetch account alias via IAM\");\n const { assumeRole } = await import(\n \"../../utils/shared/assume-role.js\"\n );\n const { IAMClient, ListAccountAliasesCommand } = await import(\n \"@aws-sdk/client-iam\"\n );\n\n const credentials = await assumeRole(config.roleArn, region);\n const iamClient = new IAMClient({ region, credentials });\n\n const response = await iamClient.send(\n new ListAccountAliasesCommand({})\n );\n\n if (response.AccountAliases && response.AccountAliases.length > 0) {\n accountAlias = response.AccountAliases[0];\n console.log(\"[User API] Account alias found:\", accountAlias);\n } else {\n console.log(\"[User API] No account alias found, using account ID\");\n }\n } else {\n console.log(\"[User API] No roleArn, skipping account alias lookup\");\n }\n } catch (error) {\n // Silently fail if we can't get account alias\n console.error(\"[User API] Error fetching account alias:\", error);\n }\n\n const responseData = {\n accountId,\n accountAlias,\n region,\n provider: metadata?.provider || \"unknown\",\n domain: metadata?.services?.email?.config?.domain || null,\n preset: metadata?.services?.email?.preset || null,\n timestamp: metadata?.timestamp || null,\n };\n\n console.log(\"[User API] Sending response:\", responseData);\n res.json(responseData);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"[User API] Error fetching user info:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n return router;\n}\n","import * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport type { DestroyOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { loadConnectionMetadata } from \"../../utils/shared/metadata.js\";\nimport { emailDestroy } from \"../email/destroy.js\";\n\n/**\n * Global Destroy command - Show services and route to service-specific destroy\n */\nexport async function destroy(options: DestroyOptions): Promise<void> {\n clack.intro(pc.bold(\"Wraps Infrastructure Teardown\"));\n\n // 1. Validate AWS credentials\n const spinner = clack.spinner();\n spinner.start(\"Validating AWS credentials\");\n\n let identity;\n try {\n identity = await validateAWSCredentials();\n spinner.stop(\"AWS credentials validated\");\n } catch (error: any) {\n spinner.stop(\"AWS credentials validation failed\");\n throw error;\n }\n\n // 2. Get region\n const region = await getAWSRegion();\n\n // 3. Load connection metadata to see what services are deployed\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n\n const deployedServices: string[] = [];\n\n if (metadata?.services?.email) {\n deployedServices.push(\"email\");\n }\n\n if (deployedServices.length === 0) {\n clack.log.warn(\"No Wraps services found in this region\");\n console.log(\n `\\nRun ${pc.cyan(\"wraps email init\")} to deploy infrastructure.\\n`\n );\n process.exit(0);\n }\n\n // 4. If only one service, destroy it directly\n if (deployedServices.length === 1) {\n const service = deployedServices[0];\n clack.log.info(`Found ${pc.cyan(service)} service deployed`);\n\n if (service === \"email\") {\n // Pass through to email destroy\n await emailDestroy(options);\n return;\n }\n }\n\n // 5. Multiple services - ask which to destroy\n const serviceToDestroy = await clack.select({\n message: \"Which service would you like to destroy?\",\n options: [\n ...deployedServices.map((s) => ({\n value: s,\n label: s.charAt(0).toUpperCase() + s.slice(1),\n hint: s === \"email\" ? \"AWS SES email infrastructure\" : undefined,\n })),\n {\n value: \"all\",\n label: \"All services\",\n hint: \"Destroy all Wraps infrastructure\",\n },\n ],\n });\n\n if (clack.isCancel(serviceToDestroy)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n // 6. Route to appropriate destroy command\n if (serviceToDestroy === \"email\" || serviceToDestroy === \"all\") {\n if (deployedServices.includes(\"email\")) {\n await emailDestroy(options);\n }\n }\n\n if (serviceToDestroy === \"all\") {\n clack.outro(pc.green(\"All Wraps infrastructure has been removed\"));\n }\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { trackCommand } from \"../../telemetry/events.js\";\nimport type { StatusOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\n\n/**\n * Global Status command - Show overview of all deployed infrastructure\n */\nexport async function status(_options: StatusOptions): Promise<void> {\n const startTime = Date.now();\n const progress = new DeploymentProgress();\n\n clack.intro(pc.bold(\"Wraps Infrastructure Status\"));\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Loading infrastructure status\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`AWS Account: ${pc.cyan(identity.accountId)}`);\n\n // 2. Get region\n const region = await getAWSRegion();\n progress.info(`Region: ${pc.cyan(region)}`);\n\n // 3. Check for deployed services\n const services: Array<{\n name: string;\n status: \"deployed\" | \"not_deployed\";\n details?: string;\n }> = [];\n\n // Check Email infrastructure\n try {\n await ensurePulumiWorkDir();\n const stack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName: `wraps-${identity.accountId}-${region}`,\n workDir: getPulumiWorkDir(),\n });\n const outputs = await stack.outputs();\n\n if (outputs.roleArn?.value) {\n const domainCount = outputs.domains?.value?.length || 0;\n services.push({\n name: \"Email\",\n status: \"deployed\",\n details: domainCount > 0 ? `${domainCount} domain(s)` : undefined,\n });\n } else {\n services.push({ name: \"Email\", status: \"not_deployed\" });\n }\n } catch (_error) {\n services.push({ name: \"Email\", status: \"not_deployed\" });\n }\n\n progress.stop();\n\n // 4. Display services overview\n console.log();\n clack.note(\n services\n .map((s) => {\n if (s.status === \"deployed\") {\n const details = s.details ? pc.dim(` (${s.details})`) : \"\";\n return ` ${pc.green(\"✓\")} ${s.name}${details}`;\n }\n return ` ${pc.dim(\"○\")} ${s.name} ${pc.dim(\"(not deployed)\")}`;\n })\n .join(\"\\n\"),\n \"Services\"\n );\n\n // 5. Show next steps\n const hasDeployedServices = services.some((s) => s.status === \"deployed\");\n\n if (hasDeployedServices) {\n console.log(`\\n${pc.bold(\"Details:\")}`);\n if (services.find((s) => s.name === \"Email\")?.status === \"deployed\") {\n console.log(\n ` ${pc.dim(\"Email:\")} ${pc.cyan(\"wraps email status\")}`\n );\n }\n } else {\n console.log(`\\n${pc.bold(\"Get started:\")}`);\n console.log(\n ` ${pc.dim(\"Deploy email:\")} ${pc.cyan(\"wraps email init\")}`\n );\n }\n\n console.log(`\\n${pc.bold(\"Dashboard:\")} ${pc.blue(\"https://app.wraps.dev\")}`);\n console.log(`${pc.bold(\"Docs:\")} ${pc.blue(\"https://wraps.dev/docs\")}\\n`);\n\n // 6. Track status command\n trackCommand(\"status\", {\n success: true,\n services_deployed: services.filter((s) => s.status === \"deployed\").length,\n duration_ms: Date.now() - startTime,\n });\n}\n","/**\n * Telemetry management commands\n * @module commands/telemetry\n */\n\nimport * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { getTelemetryClient } from \"../telemetry/client.js\";\n\n/**\n * Enable telemetry\n */\nexport async function telemetryEnable(): Promise<void> {\n const client = getTelemetryClient();\n\n client.enable();\n\n clack.log.success(pc.green(\"Telemetry enabled\"));\n console.log(` Config: ${pc.dim(client.getConfigPath())}`);\n console.log(`\\n ${pc.dim(\"Thank you for helping improve Wraps!\")}\\n`);\n}\n\n/**\n * Disable telemetry\n */\nexport async function telemetryDisable(): Promise<void> {\n const client = getTelemetryClient();\n\n client.disable();\n\n clack.log.success(pc.green(\"Telemetry disabled\"));\n console.log(` Config: ${pc.dim(client.getConfigPath())}`);\n console.log(\n `\\n ${pc.dim(\"You can re-enable with:\")} wraps telemetry enable\\n`\n );\n}\n\n/**\n * Show telemetry status\n */\nexport async function telemetryStatus(): Promise<void> {\n const client = getTelemetryClient();\n\n clack.intro(pc.bold(\"Telemetry Status\"));\n\n const status = client.isEnabled() ? pc.green(\"Enabled\") : pc.red(\"Disabled\");\n\n console.log();\n console.log(` ${pc.bold(\"Status:\")} ${status}`);\n console.log(` ${pc.bold(\"Config file:\")} ${pc.dim(client.getConfigPath())}`);\n\n // Show opt-out methods\n if (client.isEnabled()) {\n console.log();\n console.log(pc.bold(\" How to opt-out:\"));\n console.log(` ${pc.cyan(\"wraps telemetry disable\")}`);\n console.log(\n ` ${pc.dim(\"Or set:\")} ${pc.cyan(\"WRAPS_TELEMETRY_DISABLED=1\")}`\n );\n console.log(` ${pc.dim(\"Or set:\")} ${pc.cyan(\"DO_NOT_TRACK=1\")}`);\n } else {\n console.log();\n console.log(pc.bold(\" How to opt-in:\"));\n console.log(` ${pc.cyan(\"wraps telemetry enable\")}`);\n }\n\n // Show debug mode info\n console.log();\n console.log(pc.bold(\" Debug mode:\"));\n console.log(\n ` ${pc.dim(\"See what would be sent:\")} ${pc.cyan(\"WRAPS_TELEMETRY_DEBUG=1 wraps <command>\")}`\n );\n\n // Show docs link\n console.log();\n console.log(\n ` ${pc.dim(\"Learn more:\")} ${pc.cyan(\"https://wraps.dev/docs/telemetry\")}`\n );\n console.log();\n}\n","/**\n * Setup tab completion for the Wraps CLI\n *\n * This is a placeholder for future tab completion support.\n * Will integrate with tabtab or similar completion library.\n */\nexport function setupTabCompletion() {\n // Placeholder for tab completion setup\n // Will be implemented in Phase 2\n}\n\n/**\n * Print completion script for the current shell\n */\nexport function printCompletionScript() {\n console.log(\"# Wraps CLI Tab Completion\");\n console.log(\"# ========================\\n\");\n console.log(\"# Tab completion will be available in a future release.\\n\");\n console.log(\"# For now, here are the available commands:\\n\");\n console.log(\"# Email Commands:\");\n console.log(\n \"# wraps email init [--provider vercel|aws|railway|other] [--region <region>] [--domain <domain>]\"\n );\n console.log(\"# wraps email connect [--region <region>]\");\n console.log(\"# wraps email status [--account <account-id>]\");\n console.log(\"# wraps email verify --domain <domain>\");\n console.log(\"# wraps email sync\");\n console.log(\"# wraps email upgrade\");\n console.log(\"# wraps email restore [--region <region>] [--force]\");\n console.log(\"# wraps email destroy [--force] [--preview]\");\n console.log(\"# wraps email domains add --domain <domain>\");\n console.log(\"# wraps email domains list\");\n console.log(\"# wraps email domains verify --domain <domain>\");\n console.log(\"# wraps email domains get-dkim --domain <domain>\");\n console.log(\"# wraps email domains remove --domain <domain> [--force]\\n\");\n console.log(\"# Global Commands:\");\n console.log(\"# wraps status\");\n console.log(\"# wraps destroy [--force] [--preview]\");\n console.log(\"# wraps console [--port <port>] [--no-open]\");\n console.log(\"# wraps completion\");\n console.log(\"# wraps telemetry [enable|disable|status]\\n\");\n console.log(\"# Dashboard Commands:\");\n console.log(\"# wraps dashboard update-role [--region <region>] [--force]\\n\");\n console.log(\"# Flags:\");\n console.log(\"# -p, --provider : vercel, aws, railway, other\");\n console.log(\n \"# -r, --region : us-east-1, us-east-2, us-west-1, us-west-2, eu-west-1, eu-west-2, etc.\"\n );\n console.log(\"# -d, --domain : Your domain name (e.g., myapp.com)\");\n console.log(\"# --account : AWS account ID or alias\");\n console.log(\"# --preset : starter, production, enterprise, custom\");\n console.log(\"# -y, --yes : Skip confirmation prompts\");\n console.log(\"# -f, --force : Force destructive operations\");\n console.log(\"# --preview : Preview changes without deploying\\n\");\n}\n"],"mappings":";;;;;;;;;;;;;;;AACA,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAF9B;AAAA;AAAA;AAAA;AAAA;;;ACoBO,SAAS,OAAgB;AAE9B,MAAI,QAAQ,IAAI,OAAO,UAAU,QAAQ,IAAI,OAAO,KAAK;AACvD,WAAO;AAAA,EACT;AAGA,QAAM,YAAY;AAAA,IAChB;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,EACF;AAEA,SAAO,UAAU,KAAK,CAAC,WAAW,QAAQ,IAAI,MAAM,MAAM,MAAS;AACrE;AA/CA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACKA,OAAO,UAAU;AACjB,SAAS,MAAM,cAAc;AAN7B,IASM,iBAyBO;AAlCb;AAAA;AAAA;AAAA;AASA,IAAM,kBAAmC;AAAA,MACvC,SAAS;AAAA,MACT,aAAa,OAAO;AAAA,MACpB,mBAAmB;AAAA,IACrB;AAqBO,IAAM,yBAAN,MAA6B;AAAA,MACjB;AAAA,MAEjB,cAAc;AACZ,aAAK,SAAS,IAAI,KAAsB;AAAA,UACtC,aAAa;AAAA,UACb,YAAY;AAAA,UACZ,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAAA;AAAA;AAAA;AAAA,MAKA,YAAqB;AACnB,eAAO,KAAK,OAAO,IAAI,SAAS;AAAA,MAClC;AAAA;AAAA;AAAA;AAAA,MAKA,WAAW,SAAwB;AACjC,aAAK,OAAO,IAAI,WAAW,OAAO;AAAA,MACpC;AAAA;AAAA;AAAA;AAAA,MAKA,iBAAyB;AACvB,eAAO,KAAK,OAAO,IAAI,aAAa;AAAA,MACtC;AAAA;AAAA;AAAA;AAAA,MAKA,uBAAgC;AAC9B,eAAO,KAAK,OAAO,IAAI,mBAAmB;AAAA,MAC5C;AAAA;AAAA;AAAA;AAAA,MAKA,wBAA8B;AAC5B,aAAK,OAAO,IAAI,qBAAqB,IAAI;AAAA,MAC3C;AAAA;AAAA;AAAA;AAAA,MAKA,gBAAwB;AACtB,eAAO,KAAK,OAAO;AAAA,MACrB;AAAA;AAAA;AAAA;AAAA,MAKA,QAAc;AACZ,aAAK,OAAO,MAAM;AAElB,aAAK,OAAO,IAAI;AAAA,UACd,GAAG;AAAA,UACH,aAAa,OAAO;AAAA,QACtB,CAAC;AAAA,MACH;AAAA,IACF;AAAA;AAAA;;;AClGA;AAAA;AAAA;AAAA,MACE,MAAQ;AAAA,MACR,SAAW;AAAA,MACX,aAAe;AAAA,MACf,MAAQ;AAAA,MACR,MAAQ;AAAA,MACR,KAAO;AAAA,QACL,OAAS;AAAA,MACX;AAAA,MACA,OAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,YAAc;AAAA,QACZ,MAAQ;AAAA,QACR,KAAO;AAAA,QACP,WAAa;AAAA,MACf;AAAA,MACA,UAAY;AAAA,MACZ,MAAQ;AAAA,QACN,KAAO;AAAA,MACT;AAAA,MACA,eAAiB;AAAA,QACf,QAAU;AAAA,MACZ;AAAA,MACA,SAAW;AAAA,QACT,KAAO;AAAA,QACP,OAAS;AAAA,QACT,gBAAgB;AAAA,QAChB,iBAAiB;AAAA,QACjB,MAAQ;AAAA,QACR,cAAc;AAAA,QACd,WAAW;AAAA,QACX,iBAAiB;AAAA,QACjB,WAAa;AAAA,QACb,MAAQ;AAAA,QACR,gBAAkB;AAAA,MACpB;AAAA,MACA,UAAY;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,QAAU;AAAA,MACV,SAAW;AAAA,MACX,cAAgB;AAAA,QACd,uBAAuB;AAAA,QACvB,kCAAkC;AAAA,QAClC,8BAA8B;AAAA,QAC9B,8BAA8B;AAAA,QAC9B,4BAA4B;AAAA,QAC5B,uBAAuB;AAAA,QACvB,0BAA0B;AAAA,QAC1B,+BAA+B;AAAA,QAC/B,4BAA4B;AAAA,QAC5B,uBAAuB;AAAA,QACvB,yBAAyB;AAAA,QACzB,uBAAuB;AAAA,QACvB,uBAAuB;AAAA,QACvB,0BAA0B;AAAA,QAC1B,kBAAkB;AAAA,QAClB,eAAe;AAAA,QACf,kBAAkB;AAAA,QAClB,MAAQ;AAAA,QACR,MAAQ;AAAA,QACR,aAAe;AAAA,QACf,SAAW;AAAA,QACX,SAAW;AAAA,QACX,YAAY;AAAA,QACZ,mBAAmB;AAAA,QACnB,wBAAwB;AAAA,QACxB,YAAc;AAAA,QACd,MAAQ;AAAA,QACR,YAAc;AAAA,QACd,QAAU;AAAA,QACV,MAAQ;AAAA,MACV;AAAA,MACA,iBAAmB;AAAA,QACjB,eAAe;AAAA,QACf,kBAAkB;AAAA,QAClB,qBAAqB;AAAA,QACrB,eAAe;AAAA,QACf,eAAe;AAAA,QACf,uBAAuB;AAAA,QACvB,uBAAuB;AAAA,QACvB,8BAA8B;AAAA,QAC9B,QAAU;AAAA,QACV,MAAQ;AAAA,QACR,KAAO;AAAA,QACP,YAAc;AAAA,QACd,QAAU;AAAA,MACZ;AAAA,MACA,SAAW;AAAA,QACT,MAAQ;AAAA,MACV;AAAA,IACF;AAAA;AAAA;;;AC6KO,SAAS,qBAAsC;AACpD,MAAI,CAAC,mBAAmB;AACtB,wBAAoB,IAAI,gBAAgB;AAAA,EAC1C;AACA,SAAO;AACT;AApRA,IAaM,kBACA,iBAwBO,iBA8NT;AApQJ;AAAA;AAAA;AAAA;AAKA;AACA;AAOA,IAAM,mBAAmB;AACzB,IAAM,kBAAkB;AAwBjB,IAAM,kBAAN,MAAsB;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACT;AAAA,MACA,aAA+B,CAAC;AAAA,MAChC;AAAA,MAER,YAAY,UAAkC,CAAC,GAAG;AAChD,aAAK,SAAS,IAAI,uBAAuB;AACzC,aAAK,WAAW,QAAQ,YAAY;AACpC,aAAK,UAAU,QAAQ,WAAW;AAClC,aAAK,QAAQ,QAAQ,SAAS,QAAQ,IAAI,0BAA0B;AAGpE,aAAK,UAAU,KAAK,gBAAgB;AAAA,MACtC;AAAA;AAAA;AAAA;AAAA,MAKQ,kBAA2B;AAEjC,YAAI,QAAQ,IAAI,iBAAiB,KAAK;AACpC,iBAAO;AAAA,QACT;AAGA,YAAI,QAAQ,IAAI,6BAA6B,KAAK;AAChD,iBAAO;AAAA,QACT;AAGA,YAAI,KAAK,GAAG;AACV,iBAAO;AAAA,QACT;AAGA,YAAI,CAAC,KAAK,OAAO,UAAU,GAAG;AAC5B,iBAAO;AAAA,QACT;AAEA,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,MAAM,OAAe,YAA4C;AAC/D,cAAM,iBAAiC;AAAA,UACrC;AAAA,UACA,YAAY;AAAA,YACV,GAAG;AAAA,YACH,aAAa,KAAK,cAAc;AAAA,YAChC,IAAI,QAAQ;AAAA,YACZ,cAAc,QAAQ;AAAA,YACtB,IAAI,KAAK;AAAA,UACX;AAAA,UACA,aAAa,KAAK,OAAO,eAAe;AAAA,UACxC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AAGA,YAAI,KAAK,OAAO;AACd,kBAAQ;AAAA,YACN;AAAA,YACA,KAAK,UAAU,gBAAgB,MAAM,CAAC;AAAA,UACxC;AACA;AAAA,QACF;AAGA,YAAI,CAAC,KAAK,SAAS;AACjB;AAAA,QACF;AAGA,aAAK,WAAW,KAAK,cAAc;AAGnC,YAAI,KAAK,YAAY;AACnB,uBAAa,KAAK,UAAU;AAAA,QAC9B;AACA,aAAK,aAAa,WAAW,MAAM,KAAK,MAAM,GAAG,GAAG;AAAA,MACtD;AAAA;AAAA;AAAA;AAAA,MAKA,MAAc,QAAuB;AACnC,YAAI,KAAK,WAAW,WAAW,GAAG;AAChC;AAAA,QACF;AAEA,cAAM,eAAe,CAAC,GAAG,KAAK,UAAU;AACxC,aAAK,aAAa,CAAC;AAEnB,YAAI;AACF,gBAAM,aAAa,IAAI,gBAAgB;AACvC,gBAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,OAAO;AAEnE,gBAAM,cAAgC;AAAA,YACpC,QAAQ;AAAA,YACR,OAAO;AAAA,UACT;AAEA,gBAAM,MAAM,KAAK,UAAU;AAAA,YACzB,QAAQ;AAAA,YACR,SAAS;AAAA,cACP,gBAAgB;AAAA,YAClB;AAAA,YACA,MAAM,KAAK,UAAU,WAAW;AAAA,YAChC,QAAQ,WAAW;AAAA,UACrB,CAAC;AAED,uBAAa,SAAS;AAAA,QACxB,SAAS,OAAO;AAEd,cAAI,KAAK,OAAO;AACd,oBAAQ,MAAM,4CAA4C,KAAK;AAAA,UACjE;AAAA,QACF;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,MAAM,WAA0B;AAC9B,YAAI,KAAK,YAAY;AACnB,uBAAa,KAAK,UAAU;AAAA,QAC9B;AACA,cAAM,KAAK,MAAM;AAAA,MACnB;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,SAAe;AACb,aAAK,OAAO,WAAW,IAAI;AAG3B,YACE,QAAQ,IAAI,iBAAiB,OAC7B,QAAQ,IAAI,iBAAiB,QAC7B;AACA,eAAK,UAAU;AACf;AAAA,QACF;AAEA,YAAI,QAAQ,IAAI,6BAA6B,KAAK;AAChD,eAAK,UAAU;AACf;AAAA,QACF;AAEA,YAAI,KAAK,GAAG;AACV,eAAK,UAAU;AACf;AAAA,QACF;AAGA,aAAK,UAAU;AAAA,MACjB;AAAA;AAAA;AAAA;AAAA,MAKA,UAAgB;AACd,aAAK,OAAO,WAAW,KAAK;AAC5B,aAAK,UAAU;AACf,aAAK,aAAa,CAAC;AAAA,MACrB;AAAA;AAAA;AAAA;AAAA,MAKA,YAAqB;AACnB,eAAO,KAAK;AAAA,MACd;AAAA;AAAA;AAAA;AAAA,MAKA,gBAAwB;AACtB,eAAO,KAAK,OAAO,cAAc;AAAA,MACnC;AAAA;AAAA;AAAA;AAAA,MAKA,yBAAkC;AAChC,eAAO,KAAK,WAAW,CAAC,KAAK,OAAO,qBAAqB;AAAA,MAC3D;AAAA;AAAA;AAAA;AAAA,MAKA,wBAA8B;AAC5B,aAAK,OAAO,sBAAsB;AAAA,MACpC;AAAA;AAAA;AAAA;AAAA,MAKQ,gBAAwB;AAC9B,YAAI;AAGF,gBAAMA,eAAc;AACpB,iBAAOA,aAAY;AAAA,QACrB,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAGA,IAAI,oBAA4C;AAAA;AAAA;;;AC9OzC,SAAS,aACd,SACA,UAQM;AACN,QAAM,SAAS,mBAAmB;AAGlC,QAAM,YAAY,WAAW,EAAE,GAAG,SAAS,IAAI,CAAC;AAGhD,YAAU,SAAS;AACnB,YAAU,YAAY;AACtB,YAAU,QAAQ;AAElB,SAAO,MAAM,WAAW,OAAO,IAAI,SAAS;AAC9C;AAiBO,SAAS,iBACd,SACA,SACA,UAOM;AACN,QAAM,SAAS,mBAAmB;AAElC,SAAO,MAAM,gBAAgB;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,CAAC;AACH;AAgBO,SAAS,qBACd,SACA,UAMM;AACN,QAAM,SAAS,mBAAmB;AAElC,SAAO,MAAM,oBAAoB;AAAA,IAC/B;AAAA,IACA,GAAG;AAAA,EACL,CAAC;AACH;AA6DO,SAAS,WACd,WACA,SACA,UACM;AACN,QAAM,SAAS,mBAAmB;AAElC,SAAO,MAAM,kBAAkB;AAAA,IAC7B,YAAY;AAAA,IACZ;AAAA,IACA,GAAG;AAAA,EACL,CAAC;AACH;AAgBO,SAAS,aACd,SACA,UACM;AACN,QAAM,SAAS,mBAAmB;AAElC,SAAO,MAAM,WAAW,OAAO,IAAI,YAAY,CAAC,CAAC;AACnD;AAiBO,SAAS,oBACd,SACA,UAMM;AACN,QAAM,SAAS,mBAAmB;AAElC,SAAO,MAAM,oBAAoB;AAAA,IAC/B;AAAA,IACA,GAAG;AAAA,EACL,CAAC;AACH;AAaO,SAAS,oBACd,SACA,UACM;AACN,QAAM,SAAS,mBAAmB;AAElC,SAAO,MAAM,mBAAmB;AAAA,IAC9B;AAAA,IACA,GAAG;AAAA,EACL,CAAC;AACH;AArQA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;;;ACLA,YAAY,WAAW;AACvB,OAAO,QAAQ;AAsBR,SAAS,eAAe,OAAuB;AACpD,UAAQ,MAAM,EAAE;AAEhB,MAAI,iBAAiB,YAAY;AAE/B,eAAW,MAAM,MAAM,SAAS;AAEhC,IAAM,UAAI,MAAM,MAAM,OAAO;AAE7B,QAAI,MAAM,YAAY;AACpB,cAAQ,IAAI;AAAA,EAAK,GAAG,OAAO,aAAa,CAAC,EAAE;AAC3C,cAAQ,IAAI,KAAK,GAAG,MAAM,MAAM,UAAU,CAAC;AAAA,CAAI;AAAA,IACjD;AAEA,QAAI,MAAM,SAAS;AACjB,cAAQ,IAAI,GAAG,GAAG,IAAI,gBAAgB,CAAC,EAAE;AACzC,cAAQ,IAAI,KAAK,GAAG,KAAK,MAAM,OAAO,CAAC;AAAA,CAAI;AAAA,IAC7C;AAEA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,aAAW,iBAAiB,SAAS;AAErC,EAAM,UAAI,MAAM,8BAA8B;AAC9C,UAAQ,MAAM,KAAK;AACnB,UAAQ,IAAI;AAAA,EAAK,GAAG,IAAI,qCAAqC,CAAC,EAAE;AAChE,UAAQ,IAAI,KAAK,GAAG,KAAK,4CAA4C,CAAC;AAAA,CAAI;AAC1E,UAAQ,KAAK,CAAC;AAChB;AArDA,IAOa,YAmDA;AA1Db;AAAA;AAAA;AAAA;AAEA;AAKO,IAAM,aAAN,cAAyB,MAAM;AAAA,MACpC,YACE,SACO,MACA,YACA,SACP;AACA,cAAM,OAAO;AAJN;AACA;AACA;AAGP,aAAK,OAAO;AAAA,MACd;AAAA,IACF;AAyCO,IAAM,SAAS;AAAA,MACpB,kBAAkB,MAChB,IAAI;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEF,aAAa,CAAC,cACZ,IAAI;AAAA,QACF,UAAU,SAAS;AAAA,QACnB;AAAA,QACA;AAAA,mCAAoE,SAAS;AAAA,QAC7E;AAAA,MACF;AAAA,MAEF,eAAe,CAAC,WACd,IAAI;AAAA,QACF,uBAAuB,MAAM;AAAA,QAC7B;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEF,aAAa,CAAC,YACZ,IAAI;AAAA,QACF,qCAAqC,OAAO;AAAA,QAC5C;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEF,SAAS,MACP,IAAI;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEF,oBAAoB,MAClB,IAAI;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEF,aAAa,MACX,IAAI;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACJ;AAAA;AAAA;;;AClHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAS,WAAW,kCAAkC;AACtD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,0BAA0B,iBAAiB;AAepD,eAAsB,yBAA+C;AACnE,QAAM,MAAM,IAAI,UAAU,EAAE,QAAQ,YAAY,CAAC;AAEjD,MAAI;AACF,UAAM,WAAW,MAAM,IAAI,KAAK,IAAI,yBAAyB,CAAC,CAAC,CAAC;AAChE,WAAO;AAAA,MACL,WAAW,SAAS;AAAA,MACpB,QAAQ,SAAS;AAAA,MACjB,KAAK,SAAS;AAAA,IAChB;AAAA,EACF,SAAS,QAAQ;AACf,UAAM,OAAO,iBAAiB;AAAA,EAChC;AACF;AAKA,eAAsB,YAAY,QAAkC;AAElE,QAAM,eAAe;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO,aAAa,SAAS,MAAM;AACrC;AAKA,eAAsB,eAAgC;AAEpD,MAAI,QAAQ,IAAI,YAAY;AAC1B,WAAO,QAAQ,IAAI;AAAA,EACrB;AACA,MAAI,QAAQ,IAAI,oBAAoB;AAClC,WAAO,QAAQ,IAAI;AAAA,EACrB;AAGA,SAAO;AACT;AAaA,eAAsB,eAAe,QAAsC;AACzE,QAAM,MAAM,IAAI,UAAU,EAAE,OAAO,CAAC;AAEpC,MAAI;AAEF,UAAM,qBAAqB,MAAM,IAAI;AAAA,MACnC,IAAI,sBAAsB;AAAA,QACxB,cAAc;AAAA,MAChB,CAAC;AAAA,IACH;AAEA,UAAM,aAAa,mBAAmB,cAAc,CAAC;AAErD,QAAI,WAAW,WAAW,GAAG;AAC3B,aAAO,CAAC;AAAA,IACV;AAGA,UAAM,qBAAqB,MAAM,IAAI;AAAA,MACnC,IAAI,yCAAyC;AAAA,QAC3C,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AAEA,UAAM,aAAa,mBAAmB,0BAA0B,CAAC;AAGjE,WAAO,WAAW,IAAI,CAAC,YAAY;AAAA,MACjC;AAAA,MACA,UAAU,WAAW,MAAM,GAAG,uBAAuB;AAAA,IACvD,EAAE;AAAA,EACJ,SAAS,OAAO;AACd,YAAQ,MAAM,8BAA8B,KAAK;AACjD,WAAO,CAAC;AAAA,EACV;AACF;AAKA,eAAsB,aAAa,QAAkC;AACnE,QAAM,MAAM,IAAI,UAAU,EAAE,OAAO,CAAC;AAEpC,MAAI;AAGF,UAAM,IAAI;AAAA,MACR,IAAI,sBAAsB;AAAA,QACxB,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AAKA,WAAO;AAAA,EACT,SAAS,OAAY;AAEnB,QAAI,MAAM,SAAS,yBAAyB;AAC1C,aAAO;AAAA,IACT;AACA,UAAM;AAAA,EACR;AACF;AAmBA,eAAsB,wBACpB,gBACsC;AACtC,QAAMC,OAAM,IAAI,UAAU,EAAE,QAAQ,YAAY,CAAC;AAEjD,MAAI;AACF,UAAM,WAAW,MAAMA,KAAI;AAAA,MACzB,IAAI,2BAA2B;AAAA,QAC7B,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH;AAEA,UAAM,cAAc,SAAS;AAC7B,QAAI,CAAC,aAAa;AAChB,aAAO;AAAA,IACT;AAGA,UAAM,oBACJ,YAAY,yBAAyB,IAAI,CAAC,YAAY;AAAA,MACpD,MAAM,OAAO,gBAAgB,QAAQ;AAAA,MACrC,MAAM,OAAO,gBAAgB,QAAQ;AAAA,MACrC,OAAO,OAAO,gBAAgB,SAAS;AAAA,IACzC,EAAE,KAAK,CAAC;AAEV,WAAO;AAAA,MACL,QAAQ,YAAY,UAAU;AAAA,MAC9B,YAAY,YAAY,cAAc;AAAA,MACtC;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,yCAAyC,KAAK;AAC5D,WAAO;AAAA,EACT;AACF;AApNA;AAAA;AAAA;AAAA;AAOA;AAAA;AAAA;;;ACPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAWP,eAAsB,eACpB,QACA,QAC8C;AAC9C,QAAM,SAAS,IAAI,cAAc,EAAE,OAAO,CAAC;AAG3C,MAAI;AACF,UAAM,WAAW,MAAM,OAAO;AAAA,MAC5B,IAAI,6BAA6B;AAAA,QAC/B,SAAS;AAAA,QACT,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AAEA,UAAM,OAAO,SAAS,cAAc,CAAC;AACrC,QAAI,QAAQ,KAAK,SAAS,GAAG,MAAM,OAAO,KAAK,IAAI;AACjD,aAAO;AAAA,QACL,IAAI,KAAK,GAAG,QAAQ,gBAAgB,EAAE;AAAA,QACtC,MAAM,KAAK;AAAA,MACb;AAAA,IACF;AAAA,EACF,SAAS,QAAQ;AAAA,EAEjB;AAGA,QAAM,QAAQ,OAAO,MAAM,GAAG;AAC9B,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,eAAe,MAAM,MAAM,CAAC,EAAE,KAAK,GAAG;AAC5C,WAAO,eAAe,cAAc,MAAM;AAAA,EAC5C;AAEA,SAAO;AACT;AAKA,eAAsB,iBACpB,cACA,QACA,YACA,QACA,sBACA,gBACA,kBACe;AACf,QAAM,SAAS,IAAI,cAAc,EAAE,OAAO,CAAC;AAE3C,QAAM,UAAoB,CAAC;AAG3B,aAAW,SAAS,YAAY;AAC9B,YAAQ,KAAK;AAAA,MACX,QAAQ;AAAA,MACR,mBAAmB;AAAA,QACjB,MAAM,GAAG,KAAK,eAAe,MAAM;AAAA,QACnC,MAAM;AAAA,QACN,KAAK;AAAA,QACL,iBAAiB,CAAC,EAAE,OAAO,GAAG,KAAK,sBAAsB,CAAC;AAAA,MAC5D;AAAA,IACF,CAAC;AAAA,EACH;AAGA,UAAQ,KAAK;AAAA,IACX,QAAQ;AAAA,IACR,mBAAmB;AAAA,MACjB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,KAAK;AAAA,MACL,iBAAiB,CAAC,EAAE,OAAO,sCAAsC,CAAC;AAAA,IACpE;AAAA,EACF,CAAC;AAKD,QAAM,mBAAmB,iBACrB,cAAc,cAAc,KAC5B,cAAc,MAAM;AAExB,UAAQ,KAAK;AAAA,IACX,QAAQ;AAAA,IACR,mBAAmB;AAAA,MACjB,MAAM,UAAU,MAAM;AAAA,MACtB,MAAM;AAAA,MACN,KAAK;AAAA,MACL,iBAAiB;AAAA,QACf,EAAE,OAAO,uCAAuC,gBAAgB,IAAI;AAAA,MACtE;AAAA,IACF;AAAA,EACF,CAAC;AAID,MAAI,sBAAsB;AAGxB,UAAM,eAAe,oBAAoB,KAAK,MAAM;AAEpD,YAAQ,KAAK;AAAA,MACX,QAAQ;AAAA,MACR,mBAAmB;AAAA,QACjB,MAAM;AAAA,QACN,MAAM;AAAA,QACN,KAAK;AAAA,QACL,iBAAiB,CAAC,EAAE,OAAO,aAAa,CAAC;AAAA,MAC3C;AAAA,IACF,CAAC;AAAA,EACH;AAIA,MAAI,gBAAgB;AAElB,YAAQ,KAAK;AAAA,MACX,QAAQ;AAAA,MACR,mBAAmB;AAAA,QACjB,MAAM;AAAA,QACN,MAAM;AAAA,QACN,KAAK;AAAA,QACL,iBAAiB;AAAA,UACf,EAAE,OAAO,oBAAoB,MAAM,iBAAiB;AAAA,QACtD;AAAA,MACF;AAAA,IACF,CAAC;AAGD,YAAQ,KAAK;AAAA,MACX,QAAQ;AAAA,MACR,mBAAmB;AAAA,QACjB,MAAM;AAAA,QACN,MAAM;AAAA,QACN,KAAK;AAAA,QACL,iBAAiB,CAAC,EAAE,OAAO,sCAAsC,CAAC;AAAA,MACpE;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,OAAO;AAAA,IACX,IAAI,gCAAgC;AAAA,MAClC,cAAc;AAAA,MACd,aAAa;AAAA,QACX,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH;AACF;AArKA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA,YAAYC,UAAS;AAoCrB,eAAsB,qBACpBC,SACkC;AAClC,QAAM,kBAAkB,IAAQ,cAAS,iBAAiB;AAAA,IACxD,QAAQ;AAAA,EACV,CAAC;AAGD,QAAM,cAAc,IAAQ,SAAI;AAAA,IAC9B;AAAA,IACA;AAAA,MACE,YAAYA,QAAO;AAAA,MACnB,kBAAkB;AAAA,MAClB,MAAM;AAAA,QACJ,WAAW;AAAA,QACX,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA;AAAA,MACE,UAAU;AAAA,IACZ;AAAA,EACF;AAGA,QAAM,oBAAoB,YAAY,wBAAwB;AAAA,IAC5D,CAAC,YACC,QAAQ,IAAI,CAAC,YAAY;AAAA,MACvB,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,MACb,OAAO,OAAO;AAAA,IAChB,EAAE;AAAA,EACN;AAGA,MAAI;AAEJ,MAAIA,QAAO,cAAc;AAEvB,UAAM,mBAAmB,IAAQ,aAAQ;AAAA,MACvC;AAAA,MACA;AAAA,QACE,QAAQA,QAAO;AAAA,QACf,MAAM,YAAY,wBAAwB,CAAC,EAAE;AAAA,QAC7C,MAAM,YAAY,wBAAwB,CAAC,EAAE;AAAA,QAC7C,SAAS,CAAC,YAAY,wBAAwB,CAAC,EAAE,mBAAmB;AAAA,QACpE,KAAK;AAAA,MACP;AAAA,IACF;AAGA,4BAAwB,IAAQ,SAAI;AAAA,MAClC;AAAA,MACA;AAAA,QACE,gBAAgB,YAAY;AAAA,QAC5B,uBAAuB,CAAC,iBAAiB,IAAI;AAAA,MAC/C;AAAA,MACA;AAAA,QACE,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAIA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAzGA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA,YAAYC,UAAS;AAgBrB,eAAe,wBAAwB,OAAuC;AAC5E,MAAI;AACF,UAAM,EAAE,kBAAkB,yBAAyB,IAAI,MAAM,OAC3D,4BACF;AACA,UAAMC,cAAa,IAAI,iBAAiB,EAAE,QAAQ,YAAY,CAAC;AAE/D,UAAM,WAAW,MAAMA,YAAW,KAAK,IAAI,yBAAyB,CAAC,CAAC,CAAC;AAGvE,UAAM,eAAe,SAAS,kBAAkB,OAAO;AAAA,MAAK,CAAC,SAC3D,KAAK,SAAS,OAAO,SAAS,KAAK;AAAA,IACrC;AAEA,WAAO,cAAc,MAAM;AAAA,EAC7B,SAAS,OAAO;AACd,YAAQ,MAAM,0CAA0C,KAAK;AAC7D,WAAO;AAAA,EACT;AACF;AAiBA,eAAe,kBAA6C;AAE1D,QAAM,kBAAkB,IAAQ,cAAS,iBAAiB;AAAA,IACxD,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,SAAS,IAAQ,WAAM;AAAA,IAC3B;AAAA,IACA;AAAA,MACE,OAAO;AAAA;AAAA,MACP,aAAa;AAAA,MAEb,eAAe;AAAA,QACb,OAAO,CAAC;AAAA;AAAA,MACV;AAAA,MAEA,OAAO;AAAA,QACL;AAAA,UACE,MAAM;AAAA,UACN,UAAU;AAAA,UACV,QAAQ;AAAA,YACN,OAAO,CAAC;AAAA;AAAA,UACV;AAAA,UACA,WAAW;AAAA,YACT,oBAAoB;AAAA,cAClB,OAAO;AAAA;AAAA,cACP,kBAAkB;AAAA,YACpB;AAAA,UACF;AAAA,UACA,kBAAkB;AAAA,YAChB,wBAAwB;AAAA,YACxB,0BAA0B;AAAA,YAC1B,YAAY;AAAA,UACd;AAAA,QACF;AAAA,MACF;AAAA,MAEA,kBAAkB;AAAA,QAChB,wBAAwB;AAAA,QACxB,0BAA0B;AAAA,QAC1B,YAAY;AAAA,MACd;AAAA,MAEA,MAAM;AAAA,QACJ,WAAW;AAAA,QACX,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA;AAAA,MACE,UAAU;AAAA,IACZ;AAAA,EACF;AAEA,SAAO;AACT;AASA,eAAsB,yBACpBC,SAC8B;AAC9B,QAAM,oBAAoB,KAAKA,QAAO,MAAM;AAG5C,QAAM,SAAS,MAAM,gBAAgB;AAGrC,QAAM,yBAAyB,MAAM;AAAA,IACnCA,QAAO;AAAA,EACT;AAGA,QAAM,qBAAqB;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS,CAACA,QAAO,oBAAoB;AAAA;AAAA,IAGrC,UAAU,OAAO;AAAA;AAAA,IAGjB,SAAS;AAAA,MACP;AAAA,QACE,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,oBAAoB;AAAA,UAClB,UAAU;AAAA,UACV,WAAW;AAAA,UACX,sBAAsB;AAAA;AAAA,UACtB,oBAAoB,CAAC,SAAS;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAAA;AAAA,IAGA,sBAAsB;AAAA,MACpB,gBAAgB;AAAA,MAChB,sBAAsB;AAAA;AAAA,MACtB,gBAAgB,CAAC,OAAO,QAAQ,SAAS;AAAA,MACzC,eAAe,CAAC,OAAO,MAAM;AAAA;AAAA,MAG7B,iBAAiB;AAAA,QACf,aAAa;AAAA,QACb,SAAS;AAAA,UACP,SAAS;AAAA,QACX;AAAA,QACA,SAAS,CAAC,GAAG;AAAA;AAAA,MACf;AAAA;AAAA,MAGA,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,QAAQ;AAAA,MAER,UAAU;AAAA,IACZ;AAAA;AAAA,IAGA,YAAY;AAAA;AAAA,IAGZ,cAAc;AAAA,MACZ,gBAAgB;AAAA,QACd,iBAAiB;AAAA,MACnB;AAAA,IACF;AAAA;AAAA,IAGA,mBAAmB;AAAA,MACjB,mBAAmBA,QAAO;AAAA,MAC1B,kBAAkB;AAAA,MAClB,wBAAwB;AAAA,IAC1B;AAAA,IAEA,MAAM;AAAA,MACJ,WAAW;AAAA,MACX,aAAa;AAAA,IACf;AAAA,EACF;AAEA,QAAM,eAAe,yBACjB,IAAQ,gBAAW;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,MACE,QAAQ;AAAA;AAAA,IACV;AAAA,EACF,IACA,IAAQ,gBAAW;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AAMJ,SAAO;AAAA,IACL;AAAA,IACA,YAAY,aAAa;AAAA,IACzB;AAAA,EACF;AACF;AA5NA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AA2BP,SAAS,qBAAqB,WAA8C;AAC1E,UAAQ,WAAW;AAAA,IACjB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAgBA,eAAsB,yBACpBC,SACsC;AACtC,QAAM,SAASA,QAAO,UAAU,QAAQ,IAAI,cAAc;AAC1D,QAAM,cAAc,SAASA,QAAO,IAAI;AAGxC,QAAM,oBAAoB,IAAI,kBAAkB,EAAE,OAAO,CAAC;AAC1D,QAAM,YAAY,IAAI,YAAY,EAAE,OAAO,CAAC;AAE5C,QAAM,YAAYA,QAAO;AAIzB,MAAI,CAAC,WAAW;AAAA,EAehB;AAGA,QAAM,eAAe,qBAAqBA,QAAO,SAAS;AAE1D,MAAI;AACJ,MAAI;AAGJ,MAAI;AACF,UAAM,cAAc,IAAI,oBAAoB,CAAC,CAAC;AAC9C,UAAM,aAAa,MAAM,kBAAkB,KAAK,WAAW;AAE3D,UAAM,kBAAkB,WAAW,UAAU;AAAA,MAC3C,CAAC,YACC,QAAQ,gBAAgB;AAAA,IAC5B;AAEA,QAAI,iBAAiB,WAAW;AAE9B,cAAQ,IAAI,wCAAwC,WAAW,EAAE;AACjE,kBAAY,gBAAgB;AAG5B,YAAM,aAAa,IAAI,kBAAkB,EAAE,WAAW,UAAU,CAAC;AACjE,YAAM,YAAY,MAAM,kBAAkB,KAAK,UAAU;AACzD,mBAAa,UAAU;AAAA,IACzB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,IAAI,wCAAwC,KAAK;AAAA,EAE3D;AAGA,MAAI,CAAC,WAAW;AACd,QAAI;AACF,YAAM,uBAAuB,IAAI,qBAAqB;AAAA,QACpD,aAAa;AAAA,QACb,WAAW;AAAA,UACT,iBAAiB;AAAA,QACnB;AAAA,QACA,GAAI,aAAa,EAAE,WAAW,UAAU;AAAA,QACxC,MAAM;AAAA,UACJ,EAAE,KAAK,aAAa,OAAO,YAAY;AAAA,UACvC,EAAE,KAAK,QAAQ,OAAO,YAAY;AAAA,UAClC,EAAE,KAAK,aAAa,OAAOA,QAAO,UAAU;AAAA,QAC9C;AAAA,MACF,CAAC;AAED,YAAM,gBAAgB,MAAM,kBAAkB,KAAK,oBAAoB;AACvE,kBAAY,cAAc;AAE1B,UAAI,CAAC,WAAW;AACd,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAEA,cAAQ,IAAI,qCAAqC,WAAW,EAAE;AAAA,IAChE,SAAS,OAAO;AAEd,UACE,iBAAiB,SACjB,MAAM,SAAS,uBACf,MAAM,QAAQ,SAAS,wBAAwB,GAC/C;AACA,gBAAQ;AAAA,UACN;AAAA,QACF;AAGA,cAAM,cAAc,IAAI,oBAAoB,CAAC,CAAC;AAC9C,cAAM,aAAa,MAAM,kBAAkB,KAAK,WAAW;AAC3D,cAAM,kBAAkB,WAAW,UAAU;AAAA,UAC3C,CAAC,YACC,QAAQ,gBAAgB;AAAA,QAC5B;AAEA,YAAI,CAAC,iBAAiB,WAAW;AAC/B,gBAAM,IAAI;AAAA,YACR,wCAAwC,WAAW;AAAA,UACrD;AAAA,QACF;AAEA,oBAAY,gBAAgB;AAG5B,cAAM,aAAa,IAAI,kBAAkB,EAAE,WAAW,UAAU,CAAC;AACjE,cAAM,YAAY,MAAM,kBAAkB,KAAK,UAAU;AACzD,qBAAa,UAAU;AAAA,MACzB,OAAO;AACL,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,MAAI,CAAC,YAAY;AAEf,UAAM,WAAW,MAAM,OAAO,qBAAqB,EAAE;AAAA,MAAK,CAAC,MACzD,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,KAAK,IAAI,EAAE,yBAAyB,CAAC,CAAC,CAAC;AAAA,IACrE;AACA,UAAM,YAAY,SAAS;AAC3B,iBAAa,eAAe,MAAM,IAAI,SAAS,wBAAwB,SAAS;AAAA,EAClF;AAIA,QAAM,gBAAgB,MAAM,IAAI,QAAgB,CAAC,YAAY;AAC3D,IAAAA,QAAO,cAAc,MAAM,CAAC,SAAS;AACnC,cAAQ,IAAI;AAAA,IACd,CAAC;AAAA,EACH,CAAC;AAED,QAAM,6BACJ,IAAI,2CAA2C;AAAA,IAC7C,sBAAsB;AAAA,IACtB,YAAY;AAAA,EACd,CAAC;AAEH,QAAM,UAAU,KAAK,0BAA0B;AAE/C,MAAI,EAAE,aAAa,aAAa;AAC9B,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AA1PA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACkFA,SAAS,oBACP,gBACA,WACA,gBAAgB,GACR;AAER,QAAM,kBAAkB;AAGxB,QAAM,kBAAkB;AAAA,IACtB,SAAS;AAAA,IACT,UAAU;AAAA,IACV,UAAU;AAAA,IACV,WAAW;AAAA,IACX,WAAW;AAAA,IACX,WAAW;AAAA,IACX,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,WAAW;AAAA,EACb,EAAE,SAAS;AAIX,QAAM,UACJ,iBAAiB,iBAAiB,mBAAmB,MAAM;AAC7D,SAAO,UAAU,OAAO;AAC1B;AAQA,SAAS,2BACP,gBACA,WACQ;AAER,QAAM,iBAAiB;AAGvB,QAAM,kBAAkB;AAAA,IACtB,SAAS;AAAA,IACT,UAAU;AAAA,IACV,UAAU;AAAA,IACV,WAAW;AAAA,IACX,WAAW;AAAA,IACX,WAAW;AAAA,IACX,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,WAAW;AAAA,EACb,EAAE,SAAS;AAGX,QAAM,UAAU,kBAAkB,mBAAmB,MAAM;AAC3D,SAAO,UAAU,OAAO;AAC1B;AAMA,SAAS,2BACPC,SACA,gBACyB;AACzB,MAAI,CAACA,QAAO,eAAe,SAAS;AAClC;AAAA,EACF;AAEA,MAAI,cAAc;AAClB,QAAM,aAAuB,CAAC;AAG9B,QAAM,gBAAgBA,QAAO,cAAc,QAAQ,UAAU;AAC7D,QAAM,cAAc,iBAAiB;AAGrC,MAAIA,QAAO,cAAc,aAAa;AACpC,UAAM,YACH,cAAc,MAAa,YAAY;AAC1C,mBAAe;AACf,eAAW,KAAK,aAAa;AAAA,EAC/B;AAIA,QAAM,cAAc,cAAc;AAClC,QAAM,UACH,KAAK,IAAI,GAAG,cAAc,UAAU,YAAY,IAAI,MACrD,YAAY;AACd,iBAAe;AACf,aAAW,KAAK,KAAK;AAGrB,QAAM,oBAAoB;AAC1B,QAAM,oBACH,KAAK,IAAI,GAAG,oBAAoB,UAAU,eAAe,IAAI,MAC9D,YAAY;AAGd,QAAM,WAAW;AACjB,QAAM,qBAAqB;AAC3B,QAAM,mBAAmB,oBAAoB,WAAW;AACxD,QAAM,oBACJ,KAAK,IAAI,GAAG,mBAAmB,UAAU,yBAAyB,IAClE,YAAY;AAEd,iBAAe,oBAAoB;AACnC,aAAW,KAAK,QAAQ;AAExB,SAAO;AAAA,IACL,SAAS;AAAA,IACT,aAAa,qBAAqB,aAAa,iBAAiB,WAAW,KAAK,UAAK,CAAC;AAAA,EACxF;AACF;AAKA,SAAS,sBACPA,SACA,gBACyB;AACzB,MAAI,CAACA,QAAO,eAAe,iBAAiB;AAC1C;AAAA,EACF;AAEA,QAAM,YAAYA,QAAO,cAAc,oBAAoB;AAC3D,QAAM,gBAAgBA,QAAO,cAAc,QAAQ,UAAU;AAG7D,QAAM,cAAc,iBAAiB;AACrC,QAAM,YACH,KAAK,IAAI,GAAG,cAAc,UAAU,eAAe,IAAI,MACxD,YAAY;AAGd,QAAM,YAAY;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,cACJ,KAAK,IAAI,GAAG,YAAY,UAAU,mBAAmB,IACrD,YAAY;AAEd,SAAO;AAAA,IACL,SAAS,YAAY;AAAA,IACrB,aAAa,kBAAkB,SAAS,MAAM,UAAU,QAAQ,CAAC,CAAC,wBAAwB,aAAa;AAAA,EACzG;AACF;AAKA,SAAS,sBACPA,SACyB;AACzB,MAAI,CAACA,QAAO,UAAU,SAAS;AAC7B;AAAA,EACF;AAIA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AACF;AAKA,SAAS,+BACPA,SACyB;AACzB,MAAI,CAACA,QAAO,mBAAmB;AAC7B;AAAA,EACF;AAGA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AACF;AAKA,SAAS,yBACPA,SACyB;AACzB,MAAI,CAACA,QAAO,aAAa;AACvB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS,YAAY;AAAA,IACrB,aAAa;AAAA,EACf;AACF;AAMA,SAAS,4BACPA,SACA,gBACyB;AACzB,MAAI,CAACA,QAAO,gBAAgB,SAAS;AACnC;AAAA,EACF;AAEA,QAAM,YAAYA,QAAO,eAAe;AACxC,QAAM,YAAY,2BAA2B,gBAAgB,SAAS;AAGtE,QAAM,gBAAiB,iBAAiB,KAAM,OAAO;AACrD,QAAM,gBACJ,gBAAgB,YAAY;AAG9B,QAAM,cAAc,YAAY,YAAY;AAE5C,SAAO;AAAA,IACL,SAAS,gBAAgB;AAAA,IACzB,aAAa,oBAAoB,SAAS,MAAM,UAAU,QAAQ,CAAC,CAAC;AAAA,EACtE;AACF;AASO,SAAS,eACdA,SACA,iBAAiB,KACK;AACtB,QAAM,WAAW,sBAAsBA,OAAM;AAC7C,QAAM,oBAAoB,+BAA+BA,OAAM;AAC/D,QAAM,gBAAgB,2BAA2BA,SAAQ,cAAc;AACvE,QAAM,kBAAkB,sBAAsBA,SAAQ,cAAc;AACpE,QAAM,iBAAiB,4BAA4BA,SAAQ,cAAc;AACzE,QAAM,cAAc,yBAAyBA,OAAM;AAGnD,QAAM,eACJ,KAAK,IAAI,GAAG,iBAAiB,UAAU,UAAU,IACjD,YAAY;AAGd,QAAM,mBACJ,gBACC,UAAU,WAAW,MACrB,mBAAmB,WAAW,MAC9B,eAAe,WAAW,MAC1B,iBAAiB,WAAW,MAC5B,gBAAgB,WAAW,MAC3B,aAAa,WAAW;AAE3B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,MACL,SAAS;AAAA,MACT,UAAU,YAAY;AAAA,MACtB,aAAa,4BAA4B,eAAe,eAAe,CAAC;AAAA,IAC1E;AAAA,EACF;AACF;AAKO,SAAS,WAAW,MAAsB;AAC/C,MAAI,SAAS,GAAG;AACd,WAAO;AAAA,EACT;AACA,MAAI,OAAO,MAAM;AACf,WAAO;AAAA,EACT;AACA,SAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;AAC5B;AAKO,SAAS,eACdA,SACA,iBAAiB,KACT;AACR,QAAM,QAAQ,eAAeA,SAAQ,cAAc;AACnD,QAAM,QAAkB,CAAC;AAEzB,QAAM;AAAA,IACJ,sBAAsB,eAAe,eAAe,CAAC,kBAAkB,WAAW,MAAM,MAAM,OAAO,CAAC;AAAA,EACxG;AACA,QAAM;AAAA,IACJ,MAAM,YAAY,MAAM,MAAM,YAAY,KAAK,GAAI,CAAC;AAAA,EACtD;AAEA,MAAI,MAAM,UAAU;AAClB,UAAM;AAAA,MACJ,OAAO,MAAM,SAAS,WAAW,KAAK,WAAW,MAAM,SAAS,OAAO,CAAC;AAAA,IAC1E;AAAA,EACF;AACA,MAAI,MAAM,mBAAmB;AAC3B,UAAM;AAAA,MACJ,OAAO,MAAM,kBAAkB,WAAW,KAAK,WAAW,MAAM,kBAAkB,OAAO,CAAC;AAAA,IAC5F;AAAA,EACF;AACA,MAAI,MAAM,eAAe;AACvB,UAAM;AAAA,MACJ,OAAO,MAAM,cAAc,WAAW,KAAK,WAAW,MAAM,cAAc,OAAO,CAAC;AAAA,IACpF;AAAA,EACF;AACA,MAAI,MAAM,iBAAiB;AACzB,UAAM;AAAA,MACJ,OAAO,MAAM,gBAAgB,WAAW,KAAK,WAAW,MAAM,gBAAgB,OAAO,CAAC;AAAA,IACxF;AAAA,EACF;AACA,MAAI,MAAM,gBAAgB;AACxB,UAAM;AAAA,MACJ,OAAO,MAAM,eAAe,WAAW,KAAK,WAAW,MAAM,eAAe,OAAO,CAAC;AAAA,IACtF;AAAA,EACF;AACA,MAAI,MAAM,aAAa;AACrB,UAAM;AAAA,MACJ,OAAO,MAAM,YAAY,WAAW,KAAK,WAAW,MAAM,YAAY,OAAO,CAAC;AAAA,IAChF;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAhcA,IAYM,aAoCA;AAhDN;AAAA;AAAA;AAAA;AAYA,IAAM,cAAc;AAAA;AAAA,MAElB,eAAe;AAAA;AAAA,MACf,uBAAuB;AAAA;AAAA;AAAA,MAGvB,4BAA4B;AAAA;AAAA,MAC5B,2BAA2B;AAAA;AAAA,MAC3B,yBAAyB;AAAA;AAAA;AAAA,MAGzB,6BAA6B;AAAA;AAAA,MAC7B,8BAA8B;AAAA;AAAA;AAAA,MAG9B,0BAA0B;AAAA;AAAA;AAAA,MAG1B,gCAAgC;AAAA;AAAA;AAAA,MAGhC,wBAAwB;AAAA;AAAA;AAAA,MAGxB,wBAAwB;AAAA;AAAA,MACxB,gCAAgC;AAAA;AAAA;AAAA,MAGhC,+BAA+B;AAAA;AAAA,MAC/B,6BAA6B;AAAA;AAAA,IAC/B;AAMA,IAAM,YAAY;AAAA;AAAA;AAAA,MAGhB,YAAY;AAAA;AAAA;AAAA,MAGZ,iBAAiB;AAAA;AAAA,MACjB,2BAA2B;AAAA;AAAA;AAAA,MAG3B,iBAAiB;AAAA;AAAA,MACjB,gBAAgB;AAAA;AAAA,MAChB,qBAAqB;AAAA;AAAA;AAAA,MAGrB,cAAc;AAAA;AAAA;AAAA,MAGd,oBAAoB;AAAA;AAAA,IACtB;AAAA;AAAA;;;ACnEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8HO,SAAS,UAAU,QAA+C;AACvE,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAiBO,SAAS,cAAc,QAAkC;AAC9D,QAAMC,UAAS,UAAU,MAAM;AAE/B,MAAI,WAAW,YAAY,CAACA,SAAQ;AAClC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,MACb,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,eAAe;AAAA,MACf,UAAU,CAAC,gCAAgC;AAAA,IAC7C;AAAA,EACF;AAEA,QAAM,QAAQ;AAAA,IACZA;AAAA,IACA,WAAW,YACP,MACA,WAAW,eACT,MACA;AAAA,EACR;AAEA,QAAM,WAAW;AAAA,IACf,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,UAAU;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA,YAAY;AAAA,MACV,MAAM;AAAA,MACN,aAAa;AAAA,MACb,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,UAAU;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA,YAAY;AAAA,MACV,MAAM;AAAA,MACN,aAAa;AAAA,MACb,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,UAAU;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,EAAE,MAAM;AAER,SAAO;AAAA,IACL,GAAG;AAAA,IACH,eAAe,WAAW,MAAM,MAAM,OAAO;AAAA,EAC/C;AACF;AAKO,SAAS,mBAAiC;AAC/C,SAAO;AAAA,IACL,cAAc,SAAS;AAAA,IACvB,cAAc,YAAY;AAAA,IAC1B,cAAc,YAAY;AAAA,IAC1B,cAAc,QAAQ;AAAA,EACxB;AACF;AAKO,SAAS,eACd,SACA,QACU;AACV,QAAM,UAAoB,CAAC;AAG3B,MAAI,CAAC,QAAQ,UAAU,WAAW,OAAO,UAAU,SAAS;AAC1D,YAAQ,KAAK,wCAAwC;AAAA,EACvD;AAGA,MAAI,CAAC,QAAQ,qBAAqB,OAAO,mBAAmB;AAC1D,YAAQ,KAAK,2BAA2B;AAAA,EAC1C;AAGA,MAAI,CAAC,QAAQ,eAAe,WAAW,OAAO,eAAe,SAAS;AACpE,YAAQ,KAAK,iCAAiC;AAAA,EAChD;AAGA,MACE,CAAC,QAAQ,eAAe,mBACxB,OAAO,eAAe,iBACtB;AACA,YAAQ,KAAK,8BAA8B;AAAA,EAC7C;AAGA,MACE,QAAQ,eAAe,qBACrB,OAAO,eAAe,oBACxB,OAAO,eAAe,kBACtB;AACA,YAAQ;AAAA,MACN,sBAAsB,QAAQ,eAAe,oBAAoB,MAAM,WAAM,OAAO,cAAc,gBAAgB;AAAA,IACpH;AAAA,EACF;AAGA,MAAI,CAAC,QAAQ,eAAe,OAAO,aAAa;AAC9C,YAAQ,KAAK,0BAA0B;AAAA,EACzC;AAEA,SAAO;AACT;AAKO,SAAS,eAAeA,SAAoC;AACjE,QAAM,WAAqB,CAAC;AAG5B,MAAIA,QAAO,aAAa;AACtB,aAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAGA,MAAIA,QAAO,eAAe,WAAW,CAACA,QAAO,eAAe,iBAAiB;AAC3E,aAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAGA,MAAIA,QAAO,eAAe,qBAAqB,cAAc;AAC3D,aAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AA7TA,IAaa,gBA6BA,mBA0CA;AApFb;AAAA;AAAA;AAAA;AACA;AAYO,IAAM,iBAAmC;AAAA,MAC9C,UAAU;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,MACA,aAAa;AAAA,MACb,mBAAmB;AAAA,MACnB,iBAAiB;AAAA,QACf,SAAS;AAAA,QACT,SAAS,CAAC,UAAU,WAAW;AAAA,MACjC;AAAA,MACA,eAAe;AAAA,QACb,SAAS;AAAA,MACX;AAAA;AAAA,MAEA,gBAAgB;AAAA,QACd,SAAS;AAAA,QACT,WAAW;AAAA,MACb;AAAA,MACA,gBAAgB;AAAA,IAClB;AAQO,IAAM,oBAAsC;AAAA,MACjD,UAAU;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,MACA,aAAa;AAAA,MACb,mBAAmB;AAAA,MACnB,iBAAiB;AAAA,QACf,SAAS;AAAA,QACT,SAAS,CAAC,UAAU,WAAW;AAAA,MACjC;AAAA,MACA,eAAe;AAAA,QACb,SAAS;AAAA,QACT,aAAa;AAAA,QACb,QAAQ;AAAA,UACN;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,iBAAiB;AAAA,QACjB,kBAAkB;AAAA,MACpB;AAAA;AAAA,MAEA,gBAAgB;AAAA,QACd,SAAS;AAAA;AAAA,QACT,WAAW;AAAA,MACb;AAAA,MACA,gBAAgB;AAAA,IAClB;AAQO,IAAM,oBAAsC;AAAA,MACjD,UAAU;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,MACA,aAAa;AAAA,MACb,mBAAmB;AAAA,MACnB,iBAAiB;AAAA,QACf,SAAS;AAAA,QACT,SAAS,CAAC,UAAU,WAAW;AAAA,MACjC;AAAA,MACA,eAAe;AAAA,QACb,SAAS;AAAA,QACT,aAAa;AAAA,QACb,QAAQ;AAAA,UACN;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,iBAAiB;AAAA,QACjB,kBAAkB;AAAA,MACpB;AAAA;AAAA,MAEA,gBAAgB;AAAA,QACd,SAAS;AAAA;AAAA,QACT,WAAW;AAAA,MACb;AAAA,MACA,aAAa;AAAA,MACb,gBAAgB;AAAA,IAClB;AAAA;AAAA;;;ACzHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAAYC,YAAW;AACvB,OAAOC,SAAQ;AAWf,eAAsB,iBAAoC;AACxD,QAAM,WAAW,MAAY,cAAO;AAAA,IAClC,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAU,gBAAS,QAAQ,GAAG;AAC5B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO;AACT;AAKA,eAAsB,aAAa,eAAwC;AACzE,QAAM,SAAS,MAAY,cAAO;AAAA,IAChC,SAAS;AAAA,IACT,SAAS;AAAA,MACP,EAAE,OAAO,aAAa,OAAO,yBAAyB,MAAM,YAAY;AAAA,MACxE,EAAE,OAAO,aAAa,OAAO,kBAAkB,MAAM,YAAY;AAAA,MACjE;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA,EAAE,OAAO,aAAa,OAAO,oBAAoB,MAAM,YAAY;AAAA,MACnE,EAAE,OAAO,cAAc,OAAO,sBAAsB,MAAM,aAAa;AAAA,MACvE;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA,EAAE,OAAO,aAAa,OAAO,oBAAoB,MAAM,YAAY;AAAA,MACnE,EAAE,OAAO,aAAa,OAAO,mBAAmB,MAAM,YAAY;AAAA,MAClE,EAAE,OAAO,aAAa,OAAO,kBAAkB,MAAM,YAAY;AAAA,MACjE,EAAE,OAAO,cAAc,OAAO,kBAAkB,MAAM,aAAa;AAAA,MACnE,EAAE,OAAO,cAAc,OAAO,sBAAsB,MAAM,aAAa;AAAA,MACvE;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,cAAc,iBAAiB;AAAA,EACjC,CAAC;AAED,MAAU,gBAAS,MAAM,GAAG;AAC1B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO;AACT;AAKA,eAAsB,eAAgC;AACpD,QAAM,SAAS,MAAY,YAAK;AAAA,IAC9B,SAAS;AAAA,IACT,aAAa;AAAA,IACb,UAAU,CAAC,UAAU;AACnB,UAAI,CAAC,OAAO;AACV;AAAA,MACF;AACA,UAAI,CAAC,MAAM,SAAS,GAAG,GAAG;AACxB,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAU,gBAAS,MAAM,GAAG;AAC1B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO,UAAU;AACnB;AAaA,eAAsB,qBAA4C;AAChE,QAAMC,UAAS,MAAY;AAAA,IACzB;AAAA,MACE,UAAU,MACF,YAAK;AAAA,QACT,SAAS;AAAA,QACT,aAAa;AAAA,QACb,UAAU,CAAC,UAAU;AACnB,cAAI,CAAC,OAAO;AACV,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF,CAAC;AAAA,MACH,aAAa,MACL,YAAK;AAAA,QACT,SAAS;AAAA,QACT,aAAa;AAAA,QACb,UAAU,CAAC,UAAU;AACnB,cAAI,CAAC,OAAO;AACV,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACL;AAAA,IACA;AAAA,MACE,UAAU,MAAM;AACd,QAAM,cAAO,sBAAsB;AACnC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,SAAOA;AACT;AAKA,eAAsB,yBAEpB;AACA,QAAM,QAAQ,MAAY,cAAO;AAAA,IAC/B,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAU,gBAAS,KAAK,GAAG;AACzB,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO;AACT;AAKA,eAAsB,gBAAkC;AACtD,QAAM,YAAY,MAAY,eAAQ;AAAA,IACpC,SAAS;AAAA,IACT,cAAc;AAAA,EAChB,CAAC;AAED,MAAU,gBAAS,SAAS,GAAG;AAC7B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO;AACT;AAcO,SAAS,uBAAwC;AACtD,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAKA,eAAsB,uBACpB,aACmB;AACnB,QAAM,WAAW,qBAAqB;AAEtC,QAAM,WAAW,MAAY,mBAAY;AAAA,IACvC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,eAAe,eAAe;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,UAAU;AAAA,EACZ,CAAC;AAED,MAAU,gBAAS,QAAQ,GAAG;AAC5B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO;AACT;AAUA,eAAsB,yBACpB,cACA,sBACyB;AACzB,QAAM,SAAS,MAAY,cAAO;AAAA,IAChC,SAAS,kBAAkB,YAAY,KAAKD,IAAG,KAAK,oBAAoB,CAAC;AAAA,IACzE,SAAS;AAAA,MACP;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAU,gBAAS,MAAM,GAAG;AAC1B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO;AACT;AAKA,eAAsB,uBACpB,YACmB;AACnB,QAAM,WAAW,MAAY,mBAAY;AAAA,IACvC,SAAS;AAAA,IACT,SAAS,WAAW,IAAI,CAAC,QAAQ;AAAA,MAC/B,OAAO,GAAG;AAAA,MACV,OAAO,GAAG;AAAA,MACV,MAAM,GAAG,WAAW,aAAa;AAAA,IACnC,EAAE;AAAA,IACF,UAAU;AAAA,EACZ,CAAC;AAED,MAAU,gBAAS,QAAQ,GAAG;AAC5B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO;AACT;AAKA,eAAsB,iBAAmC;AACvD,QAAM,YAAY,MAAY,eAAQ;AAAA,IACpC,SAAS;AAAA,IACT,cAAc;AAAA,EAChB,CAAC;AAED,MAAU,gBAAS,SAAS,GAAG;AAC7B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO;AACT;AAKA,eAAsB,qBAEpB;AACA,QAAM,EAAE,kBAAAE,kBAAiB,IAAI,MAAM;AACnC,QAAM,UAAUA,kBAAiB;AAEjC,QAAM,SAAS,MAAY,cAAO;AAAA,IAChC,SAAS;AAAA,IACT,SAAS,QAAQ,IAAI,CAAC,OAAY;AAAA,MAChC,OAAO,EAAE,KAAK,YAAY;AAAA,MAK1B,OAAO,GAAG,EAAE,IAAI,MAAM,EAAE,WAAW;AAAA,MACnC,MAAM,GAAG,EAAE,MAAM,WAAW,EAAE,aAAa;AAAA,IAC7C,EAAE;AAAA,EACJ,CAAC;AAED,MAAU,gBAAS,MAAM,GAAG;AAC1B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO;AACT;AAKA,eAAsB,wBAAyC;AAC7D,QAAM,SAAS,MAAY,cAAO;AAAA,IAChC,SAAS;AAAA,IACT,SAAS;AAAA,MACP,EAAE,OAAO,KAAM,OAAO,qBAAqB,MAAM,oBAAoB;AAAA,MACrE,EAAE,OAAO,KAAQ,OAAO,uBAAuB,MAAM,eAAe;AAAA,MACpE;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA,EAAE,OAAO,KAAW,OAAO,sBAAsB,MAAM,cAAc;AAAA,IACvE;AAAA,EACF,CAAC;AAED,MAAU,gBAAS,MAAM,GAAG;AAC1B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO;AACT;AAQA,eAAsB,uBAGnB;AACD,QAAM,UAAU,MAAY,eAAQ;AAAA,IAClC,SACE;AAAA,IACF,cAAc;AAAA,EAChB,CAAC;AAED,MAAU,gBAAS,OAAO,GAAG;AAC3B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,CAAC,SAAS;AACZ,WAAO,EAAE,SAAS,OAAO,WAAW,SAAS;AAAA,EAC/C;AAEA,QAAM,YAAY,MAAY,cAAO;AAAA,IACnC,SAAS;AAAA,IACT,SAAS;AAAA,MACP,EAAE,OAAO,SAAS,OAAO,UAAU,MAAM,0BAA0B;AAAA,MACnE,EAAE,OAAO,UAAU,OAAO,WAAW,MAAM,0BAA0B;AAAA,MACrE;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA,EAAE,OAAO,SAAS,OAAO,UAAU,MAAM,4BAA4B;AAAA,MACrE;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,cAAc;AAAA,EAChB,CAAC;AAED,MAAU,gBAAS,SAAS,GAAG;AAC7B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,EAAM,WAAI;AAAA,IACRF,IAAG;AAAA,MACD;AAAA,IACF;AAAA,EACF;AACA,EAAM,WAAI;AAAA,IACRA,IAAG,IAAI,kEAAkE;AAAA,EAC3E;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,EACF;AACF;AAEA,eAAsB,mBAAmB,gBAAoC;AAC3E,EAAM,WAAI,KAAK,8BAA8B;AAC7C,EAAM,WAAI,KAAK,qCAAqC;AAGpD,QAAM,oBAAoB,MAAY,eAAQ;AAAA,IAC5C,SAAS;AAAA,IACT,cAAc,gBAAgB,qBAAqB;AAAA,EACrD,CAAC;AAED,MAAU,gBAAS,iBAAiB,GAAG;AACrC,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,kBAAkB,MAAY,eAAQ;AAAA,IAC1C,SAAS;AAAA,IACT,cAAc,gBAAgB,UAAU,WAAW;AAAA,EACrD,CAAC;AAED,MAAU,gBAAS,eAAe,GAAG;AACnC,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,uBAAuB,MAAY,eAAQ;AAAA,IAC/C,SAAS;AAAA,IACT,cAAc,gBAAgB,eAAe,WAAW;AAAA,EAC1D,CAAC;AAED,MAAU,gBAAS,oBAAoB,GAAG;AACxC,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,mBAAoC;AAExC,MAAI,sBAAsB;AACxB,uBAAmB,MAAY,cAAO;AAAA,MACpC,SAAS;AAAA,MACT,SAAS;AAAA,QACP,EAAE,OAAO,SAAS,OAAO,UAAU,MAAM,uBAAuB;AAAA,QAChE,EAAE,OAAO,UAAU,OAAO,WAAW,MAAM,sBAAsB;AAAA,QACjE;AAAA,UACE,OAAO;AAAA,UACP,OAAO;AAAA,UACP,MAAM;AAAA,QACR;AAAA,QACA,EAAE,OAAO,SAAS,OAAO,UAAU,MAAM,0BAA0B;AAAA,QACnE;AAAA,UACE,OAAO;AAAA,UACP,OAAO;AAAA,UACP,MAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,cACE,gBAAgB,eAAe,oBAAoB;AAAA,IACvD,CAAC;AAED,QAAU,gBAAS,gBAAgB,GAAG;AACpC,MAAM,cAAO,sBAAsB;AACnC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAGA,QAAM,cAAc,MAAY,eAAQ;AAAA,IACtC,SAAS;AAAA,IACT,cAAc,gBAAgB,eAAe;AAAA,EAC/C,CAAC;AAED,MAAU,gBAAS,WAAW,GAAG;AAC/B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,iBAAiB,MAAY,eAAQ;AAAA,IACzC,SAAS;AAAA,IACT,cAAc,gBAAgB,mBAAmB;AAAA,EACnD,CAAC;AAED,MAAU,gBAAS,cAAc,GAAG;AAClC,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,oBAAqC;AAEzC,MAAI,gBAAgB;AAClB,wBAAoB,MAAY,YAAK;AAAA,MACnC,SAAS;AAAA,MACT,aAAa;AAAA,MACb,cACE,gBAAgB,gBAAgB,MAAM,GAAG,EAAE,CAAC,KAAK;AAAA,MACnD,UAAU,CAAC,UAAU;AACnB,YAAI,CAAC,SAAS,MAAM,KAAK,MAAM,IAAI;AACjC,iBAAO;AAAA,QACT;AACA,YAAI,CAAC,mCAAmC,KAAK,KAAK,GAAG;AACnD,iBAAO;AAAA,QACT;AACA,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAED,QAAU,gBAAS,iBAAiB,GAAG;AACrC,MAAM,cAAO,sBAAsB;AACnC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,IAAM,WAAI;AAAA,MACRA,IAAG;AAAA,QACD,4BAA4B,iBAAiB;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AAGA,QAAM,cAAc,MAAY,eAAQ;AAAA,IACtC,SAAS;AAAA,IACT,cAAc,gBAAgB,eAAe;AAAA,EAC/C,CAAC;AAED,MAAU,gBAAS,WAAW,GAAG;AAC/B,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,wBAAwB,MAAY,eAAQ;AAAA,IAChD,SACE;AAAA,IACF,cAAc,gBAAgB,gBAAgB,WAAW;AAAA,EAC3D,CAAC;AAED,MAAU,gBAAS,qBAAqB,GAAG;AACzC,IAAM,cAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,wBAAyC;AAE7C,MAAI,uBAAuB;AACzB,4BAAwB,MAAY,cAAO;AAAA,MACzC,SAAS;AAAA,MACT,SAAS;AAAA,QACP,EAAE,OAAO,SAAS,OAAO,UAAU,MAAM,0BAA0B;AAAA,QACnE,EAAE,OAAO,UAAU,OAAO,WAAW,MAAM,0BAA0B;AAAA,QACrE;AAAA,UACE,OAAO;AAAA,UACP,OAAO;AAAA,UACP,MAAM;AAAA,QACR;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,OAAO;AAAA,UACP,MAAM;AAAA,QACR;AAAA,QACA,EAAE,OAAO,SAAS,OAAO,UAAU,MAAM,4BAA4B;AAAA,QACrE;AAAA,UACE,OAAO;AAAA,UACP,OAAO;AAAA,UACP,MAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,cAAc,gBAAgB,gBAAgB,aAAa;AAAA,IAC7D,CAAC;AAED,QAAU,gBAAS,qBAAqB,GAAG;AACzC,MAAM,cAAO,sBAAsB;AACnC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,IAAM,WAAI;AAAA,MACRA,IAAG;AAAA,QACD;AAAA,MACF;AAAA,IACF;AACA,IAAM,WAAI;AAAA,MACRA,IAAG,IAAI,kEAAkE;AAAA,IAC3E;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU,kBACN;AAAA,MACE,SAAS;AAAA,MACT,OAAO;AAAA,MACP,QAAQ;AAAA,IACV,IACA,EAAE,SAAS,MAAM;AAAA,IACrB;AAAA,IACA;AAAA,IACA,mBAAmB,iBACf,OAAO,sBAAsB,WAC3B,oBACA,SACF;AAAA,IACJ,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,SAAS,CAAC,UAAU,WAAW;AAAA,IACjC;AAAA,IACA,eAAe,uBACX;AAAA,MACE,SAAS;AAAA,MACT,aAAa;AAAA,MACb,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,iBAAiB;AAAA,MACjB,kBACE,OAAO,qBAAqB,WAAW,mBAAmB;AAAA,IAC9D,IACA,EAAE,SAAS,MAAM;AAAA,IACrB,gBAAgB,wBACZ;AAAA,MACE,SAAS;AAAA,MACT,WACE,OAAO,0BAA0B,WAC7B,wBACA;AAAA,IACR,IACA,EAAE,SAAS,OAAO,WAAW,SAAS;AAAA,IAC1C;AAAA,IACA,gBAAgB;AAAA,EAClB;AACF;AA9wBA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA,SAAS,mBAAmB,aAAAG,kBAAiB;AAe7C,eAAsB,WACpB,SACA,QACA,cAAc,iBACkB;AAChC,QAAM,MAAM,IAAIA,WAAU,EAAE,OAAO,CAAC;AAEpC,QAAM,WAAW,MAAM,IAAI;AAAA,IACzB,IAAI,kBAAkB;AAAA,MACpB,SAAS;AAAA,MACT,iBAAiB;AAAA,MACjB,iBAAiB;AAAA;AAAA,IACnB,CAAC;AAAA,EACH;AAEA,MAAI,CAAC,SAAS,aAAa;AACzB,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AAEA,SAAO;AAAA,IACL,aAAa,SAAS,YAAY;AAAA,IAClC,iBAAiB,SAAS,YAAY;AAAA,IACtC,cAAc,SAAS,YAAY;AAAA,IACnC,YAAY,SAAS,YAAY;AAAA,EACnC;AACF;AAxCA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA,EACE;AAAA,EAEA;AAAA,EACA,qBAAAC;AAAA,EACA;AAAA,OACK;AACP,OAAO,eAAe;AACtB,SAA0B,oBAAoB;AAgC9C,SAAS,iBAAiB,gBAAgC;AACxD,MAAI,eAAe,WAAW,MAAM,GAAG;AAErC,UAAM,QAAQ,eAAe,MAAM,GAAG;AACtC,WAAO,MAAM,GAAG,EAAE;AAAA,EACpB;AAEA,SAAO;AACT;AA2BA,eAAsB,iBACpB,gBACA,gBACA,QACsB;AACtB,QAAM,SAAS,IAAIA,mBAAkB,EAAE,OAAO,CAAC;AAG/C,QAAM,YAAY,iBAAiB,cAAc;AAKjD,QAAM,aAAa,eAAe,aAAa,oBAAI,KAAK;AACxD,QAAM,YAAY,IAAI,KAAK,WAAW,QAAQ,IAAI,KAAK,KAAK,KAAK,GAAI;AACrE,QAAM,WAAW,IAAI,KAAK,WAAW,QAAQ,IAAI,KAAK,KAAK,KAAK,GAAI;AAGpE,QAAM,UAAiB,CAAC;AAExB,MAAI,eAAe,MAAM;AACvB,YAAQ,KAAK;AAAA,MACX,kBAAkB;AAAA,QAChB,UAAU;AAAA,UACR,WAAW;AAAA,QACb;AAAA,QACA,UAAU;AAAA,QACV,QAAQ,CAAC,eAAe,IAAI;AAAA,MAC9B;AAAA,IACF,CAAC;AAAA,EACH;AAEA,MAAI,eAAe,IAAI;AACrB,YAAQ,KAAK;AAAA,MACX,kBAAkB;AAAA,QAChB,UAAU;AAAA,UACR,WAAW;AAAA,QACb;AAAA,QACA,UAAU;AAAA,QACV,QAAQ,CAAC,eAAe,EAAE;AAAA,MAC5B;AAAA,IACF,CAAC;AAAA,EACH;AAEA,MAAI,eAAe,SAAS;AAC1B,YAAQ,KAAK;AAAA,MACX,kBAAkB;AAAA,QAChB,UAAU;AAAA,UACR,WAAW;AAAA,QACb;AAAA,QACA,UAAU;AAAA,QACV,QAAQ,CAAC,eAAe,OAAO;AAAA,MACjC;AAAA,IACF,CAAC;AAAA,EACH;AAGA,MAAI,QAAQ,WAAW,GAAG;AACxB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,gBAAgB,IAAI,0BAA0B;AAAA,IAClD,WAAW;AAAA,IACX,eAAe;AAAA,IACf,aAAa;AAAA,IACb,SAAS;AAAA,MACP,SAAS;AAAA,IACX;AAAA,IACA,YAAY;AAAA;AAAA,EACd,CAAC;AAED,QAAM,iBAAiB,MAAM,OAAO,KAAK,aAAa;AACtD,QAAM,WAAW,eAAe;AAEhC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAGA,MAAI;AACJ,MAAI,WAAW;AACf,QAAM,cAAc;AACpB,QAAM,eAAe;AAGrB,QAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAI,CAAC;AAExD,SAAO,WAAW,aAAa;AAC7B,QAAI;AACF,YAAM,iBAAiB,IAAI,+BAA+B;AAAA,QACxD,UAAU;AAAA,MACZ,CAAC;AAED,YAAM,kBAAkB,MAAM,OAAO,KAAK,cAAc;AAExD,UAAI,gBAAgB,QAAQ,gBAAgB,KAAK,SAAS,GAAG;AAE3D,4BAAoB,gBAAgB,KAAK,CAAC,EAAE;AAC5C;AAAA,MACF;AAGA,UAAI,gBAAgB,QAAQ,gBAAgB,KAAK,WAAW,GAAG;AAE7D;AAAA,MACF;AAAA,IACF,SAAS,OAAgB;AAEvB,UACE,iBAAiB,SACjB,MAAM,SAAS,uBACf,MAAM,QAAQ,SAAS,mBAAmB,GAC1C;AACA,gBAAQ,IAAI,qCAAqC,WAAW,CAAC,KAAK;AAAA,MACpE,OAAO;AAEL,cAAM;AAAA,MACR;AAAA,IACF;AAGA,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,YAAY,CAAC;AAChE;AAAA,EACF;AAEA,MAAI,CAAC,mBAAmB;AACtB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,QAAM,UAAU,IAAI,yBAAyB;AAAA,IAC3C,mBAAmB;AAAA,EACrB,CAAC;AAED,QAAM,WAA2C,MAAM,OAAO,KAAK,OAAO;AAE1E,MAAI,CAAC,SAAS,qBAAqB;AACjC,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AAGA,QAAM,gBAAgB,MAAM,MAAM,SAAS,mBAAmB;AAC9D,MAAI,CAAC,cAAc,IAAI;AACrB,UAAM,IAAI,MAAM,6BAA6B,cAAc,UAAU,EAAE;AAAA,EACzE;AAEA,QAAM,WAAW,MAAM,cAAc,KAAK;AAG1C,QAAM,SAAqB,MAAM,aAAa,QAAQ;AAGtD,QAAM,cACJ,OAAO,aAAa,IAAI,CAAC,SAAS;AAAA,IAChC,UAAU,IAAI;AAAA,IACd,aAAa,IAAI;AAAA,IACjB,MAAM,IAAI;AAAA,EACZ,EAAE,KAAK,CAAC;AAGV,QAAM,UAAyD,CAAC;AAChE,MAAI,OAAO,SAAS;AAClB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,SAAS;AAEzC,UAAI,iBAAiB,MAAM;AACzB,gBAAQ,GAAG,IAAI,MAAM,YAAY;AAAA,MACnC,WAAW,OAAO,UAAU,UAAU;AACpC,gBAAQ,GAAG,IAAI;AAAA,MACjB,WACE,MAAM,QAAQ,KAAK,KACnB,MAAM,MAAM,CAAC,MAAM,OAAO,MAAM,QAAQ,GACxC;AACA,gBAAQ,GAAG,IAAI;AAAA,MACjB,OAAO;AAEL,gBAAQ,GAAG,IAAI,KAAK,UAAU,KAAK;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AAGA,QAAM,iBAAiB,CACrB,SACW;AACX,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,IACT;AACA,QAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,aAAO,KAAK,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI;AAAA,IAC1C;AACA,WAAO,KAAK,QAAQ;AAAA,EACtB;AAEA,SAAO;AAAA,IACL,WAAW,OAAO,aAAa,QAAQ,YAAY,GAAG,SAAS,KAAK;AAAA,IACpE,MAAM,eAAe,OAAO,IAAI;AAAA,IAChC,IAAI,eAAe,OAAO,EAAE;AAAA,IAC5B,SAAS,OAAO,WAAW;AAAA,IAC3B,MAAM,OAAO,QAAQ;AAAA,IACrB,MAAM,OAAO,QAAQ;AAAA,IACrB;AAAA,IACA;AAAA,IACA,WAAW,OAAO,QAAQ,oBAAI,KAAK;AAAA;AAAA;AAAA,IAGnC,UAAU,CAAC;AAAA,EACb;AACF;AA9RA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAkDA,eAAsB,mBACpB,WACA,SAC+B;AAC/B,QAAM,EAAE,QAAQ,YAAY,MAAM,IAAI,SAAS,UAAU,IAAI;AAE7D,MAAI;AACF,YAAQ,IAAI,4BAA4B;AAAA,MACtC;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAGD,UAAM,iBAAwC;AAAA,MAC5C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAGA,UAAM,QAAQ,MAAM,iBAAiB,YAAY,gBAAgB,MAAM;AAEvE,YAAQ,IAAI,wCAAwC;AAAA,MAClD,WAAW,MAAM;AAAA,MACjB,SAAS,CAAC,CAAC,MAAM;AAAA,MACjB,SAAS,CAAC,CAAC,MAAM;AAAA,MACjB,iBAAiB,MAAM,YAAY;AAAA,IACrC,CAAC;AAGD,WAAO;AAAA,EACT,SAAS,OAAgB;AAEvB,QACE,iBAAiB,UAChB,MAAM,QAAQ,SAAS,WAAW,KACjC,MAAM,QAAQ,SAAS,2BAA2B,IACpD;AACA,cAAQ,IAAI,6BAA6B,SAAS;AAClD,aAAO;AAAA,IACT;AAGA,YAAQ,MAAM,kCAAkC,KAAK;AACrD,UAAM;AAAA,EACR;AACF;AAlGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA,SAAS,kBAAAC,iBAAgB,eAAAC,oBAAmB;AAC5C,SAAS,cAAAC,mBAAkB;AAU3B,eAAsB,qBACpB,QACA,WACA,WAC0B;AAC1B,QAAMC,YAAW,IAAIH,gBAAe,EAAE,OAAO,CAAC;AAE9C,MAAI;AACF,UAAM,YAAY,UAAU,MAAM,QAAQ;AAC1C,UAAM,UAAU,UAAU,IAAI,QAAQ;AAItC,UAAM,WAAW,MAAMG,UAAS;AAAA,MAC9B,IAAIF,aAAY;AAAA,QACd,WAAW;AAAA,QACX,kBACE;AAAA,QACF,2BAA2B;AAAA,UACzB,cAAc,EAAE,GAAG,UAAU,SAAS,EAAE;AAAA,UACxC,YAAY,EAAE,GAAG,QAAQ,SAAS,EAAE;AAAA,UACpC,SAAS,EAAE,GAAG,OAAO;AAAA,UACrB,UAAU,EAAE,GAAG,QAAQ;AAAA,QACzB;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,SAAS,SAAS,SAAS,CAAC,GAAG,IAAI,CAAC,SAASC,YAAW,IAAI,CAAC;AAGnE,UAAM,SAAS,IAAI,KAAK;AACxB,UAAM,cAAc,oBAAI,IAAoB;AAC5C,UAAM,eAAe,oBAAI,IAAoB;AAE7C,eAAW,QAAQ,OAAO;AACxB,YAAM,YAAY,OAAO,KAAK,MAAM;AACpC,YAAM,SAAS,KAAK,MAAM,YAAY,MAAM,IAAI;AAChD,YAAM,YAAY,KAAK;AAEvB,UAAI,cAAc,QAAQ;AACxB,oBAAY,IAAI,SAAS,YAAY,IAAI,MAAM,KAAK,KAAK,CAAC;AAAA,MAC5D,WAAW,cAAc,SAAS;AAChC,qBAAa,IAAI,SAAS,aAAa,IAAI,MAAM,KAAK,KAAK,CAAC;AAAA,MAC9D;AAAA,IACF;AAGA,UAAM,QAAQ,MAAM,KAAK,YAAY,QAAQ,CAAC,EAAE;AAAA,MAC9C,CAAC,CAAC,WAAW,KAAK,OAAO;AAAA,QACvB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,KAAK,aAAa,QAAQ,CAAC,EAAE;AAAA,MAChD,CAAC,CAAC,WAAW,KAAK,OAAO;AAAA,QACvB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,OAAO,MAAM,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAAA,MACrD,QAAQ,OAAO,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAAA,IACzD;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,oCAAoC,KAAK;AAEvD,WAAO;AAAA,MACL,OAAO,CAAC;AAAA,MACR,QAAQ,CAAC;AAAA,IACX;AAAA,EACF;AACF;AApFA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AACA,SAAS,oBAAoB;AAC7B,SAAS,WAAAE,UAAS,QAAAC,aAAY;AAC9B,SAAS,iBAAAC,sBAAqB;AAC9B,YAAYC,aAAW;AACvB,OAAO,UAAU;AACjB,OAAOC,UAAQ;;;ACNf;AAIA;AAJA,SAAS,gBAAgB,iBAAiB;AAC1C,SAAS,SAAS,SAAAC,QAAO,UAAU,OAAAC,MAAK,SAAAC,cAAa;AACrD,OAAOC,SAAQ;;;ACFf;AAAA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,UAAU,iBAAiB;AACpC,SAAS,QAAAC,aAAY;;;ACFrB;AAAA,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,eAAe;AACxB,SAAS,YAAY;AAKd,SAAS,cAAsB;AACpC,SAAO,KAAK,QAAQ,GAAG,QAAQ;AACjC;AAKO,SAAS,mBAA2B;AACzC,SAAO,KAAK,YAAY,GAAG,QAAQ;AACrC;AAKA,eAAsB,iBAAgC;AACpD,QAAM,WAAW,YAAY;AAC7B,MAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,UAAM,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,EAC3C;AACF;AAKA,eAAsB,sBAAqC;AACzD,QAAM,eAAe;AACrB,QAAM,YAAY,iBAAiB;AACnC,MAAI,CAAC,WAAW,SAAS,GAAG;AAC1B,UAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,EAC5C;AAIA,UAAQ,IAAI,qBAAqB,UAAU,SAAS;AACpD,UAAQ,IAAI,2BAA2B;AACzC;;;ADsBA,SAAS,oBAA4B;AACnC,SAAOC,MAAK,YAAY,GAAG,aAAa;AAC1C;AAKA,SAAS,gBAAgB,WAAmB,QAAwB;AAClE,SAAOA,MAAK,kBAAkB,GAAG,GAAG,SAAS,IAAI,MAAM,OAAO;AAChE;AAKA,eAAe,uBAAsC;AACnD,QAAM,eAAe;AACrB,QAAM,iBAAiB,kBAAkB;AACzC,MAAI,CAACC,YAAW,cAAc,GAAG;AAC/B,UAAM,EAAE,OAAAC,OAAM,IAAI,MAAM,OAAO,aAAkB;AACjD,UAAMA,OAAM,gBAAgB,EAAE,WAAW,KAAK,CAAC;AAAA,EACjD;AACF;AAKA,SAAS,sBACP,QACoB;AACpB,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW,OAAO;AAAA,IAClB,QAAQ,OAAO;AAAA,IACf,UAAU,OAAO;AAAA,IACjB,WAAW,OAAO;AAAA,IAClB,QAAQ,OAAO;AAAA,IACf,UAAU;AAAA,MACR,OAAO;AAAA,QACL,QAAQ,OAAO;AAAA,QACf,QAAQ,OAAO;AAAA,QACf,iBAAiB,OAAO;AAAA,QACxB,YAAY,OAAO;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AACF;AAKA,SAAS,iBAAiB,MAA6C;AACrE,SACE,iBAAiB,QACjB,EAAE,cAAc,SAChB,OAAO,KAAK,gBAAgB;AAEhC;AAMA,eAAsB,uBACpB,WACA,QACoC;AACpC,QAAM,eAAe,gBAAgB,WAAW,MAAM;AAEtD,MAAI,CAACD,YAAW,YAAY,GAAG;AAC7B,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,cAAc,OAAO;AACpD,UAAM,OAAO,KAAK,MAAM,OAAO;AAG/B,QAAI,iBAAiB,IAAI,GAAG;AAC1B,YAAM,WAAW,sBAAsB,IAAI;AAE3C,YAAM,uBAAuB,QAAQ;AACrC,aAAO;AAAA,IACT;AAGA,QAAI,CAAC,KAAK,SAAS;AACjB,WAAK,UAAU;AACf,YAAM,uBAAuB,IAAI;AAAA,IACnC;AAEA,WAAO;AAAA,EACT,SAAS,OAAY;AACnB,YAAQ,MAAM,sCAAsC,MAAM,OAAO;AACjE,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,uBACpB,UACe;AACf,QAAM,qBAAqB;AAC3B,QAAM,eAAe,gBAAgB,SAAS,WAAW,SAAS,MAAM;AAExE,MAAI;AACF,UAAM,UAAU,KAAK,UAAU,UAAU,MAAM,CAAC;AAChD,UAAM,UAAU,cAAc,SAAS,OAAO;AAAA,EAChD,SAAS,OAAY;AACnB,YAAQ,MAAM,qCAAqC,MAAM,OAAO;AAChE,UAAM;AAAA,EACR;AACF;AAKA,eAAsB,yBACpB,WACA,QACe;AACf,QAAM,eAAe,gBAAgB,WAAW,MAAM;AAEtD,MAAIA,YAAW,YAAY,GAAG;AAC5B,UAAM,EAAE,OAAO,IAAI,MAAM,OAAO,aAAkB;AAClD,UAAM,OAAO,YAAY;AAAA,EAC3B;AACF;AAmDO,SAAS,yBACd,WACA,QACA,UACA,aACA,QACoB;AACpB,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,UAAU;AAAA,MACR,OAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,QACR,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AACF;AAYO,SAAS,mBACd,gBACA,SACkB;AAElB,QAAM,SAAS,EAAE,GAAG,eAAe;AAGnC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,QAAI,UAAU,QAAW;AACvB;AAAA,IACF;AAEA,QAAI,QAAQ,cAAc,OAAO,UAAU,UAAU;AAEnD,YAAM,iBAAiB;AACvB,aAAO,WAAW;AAAA,QAChB,GAAG,OAAO;AAAA,QACV,GAAG;AAAA;AAAA,QAEH,sBACE,OAAO,UAAU,wBACjB,eAAe;AAAA,QACjB,cACE,OAAO,UAAU,gBAAgB,eAAe;AAAA,MACpD;AAAA,IACF,WAAW,QAAQ,mBAAmB,OAAO,UAAU,UAAU;AAE/D,aAAO,gBAAgB;AAAA,QACrB,GAAG,OAAO;AAAA,QACV,GAAI;AAAA,MACN;AAAA,IACF,WAAW,QAAQ,qBAAqB,OAAO,UAAU,UAAU;AAEjE,aAAO,kBAAkB;AAAA,QACvB,GAAG,OAAO;AAAA,QACV,GAAI;AAAA,MACN;AAAA,IACF,WAAW,QAAQ,oBAAoB,OAAO,UAAU,UAAU;AAEhE,aAAO,iBAAiB;AAAA,QACtB,GAAG,OAAO;AAAA,QACV,GAAI;AAAA,MACN;AAAA,IACF,OAAO;AAEL,aAAO,GAA6B,IAAI;AAAA,IAC1C;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,kBACd,UACA,aACM;AACN,MAAI,CAAC,SAAS,SAAS,OAAO;AAC5B,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAGA,WAAS,SAAS,MAAM,SAAS;AAAA,IAC/B,SAAS,SAAS,MAAM;AAAA,IACxB;AAAA,EACF;AAEA,WAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC9C;;;AE7VA;AAAA,YAAYE,YAAW;AACvB,OAAOC,SAAQ;AAKR,IAAM,qBAAN,MAAyB;AAAA,EACtB,iBAA0D;AAAA;AAAA;AAAA;AAAA,EAKlE,MAAM,SAAiB;AACrB,SAAK,iBAAuB,eAAQ;AACpC,SAAK,eAAe,MAAM,OAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,SAAiB;AACvB,QAAI,KAAK,gBAAgB;AACvB,WAAK,eAAe,KAAK,OAAO;AAAA,IAClC;AACA,IAAM,WAAI,QAAQ,OAAO;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,SAAiB;AACpB,QAAI,KAAK,gBAAgB;AACvB,WAAK,eAAe,KAAK,OAAO;AAAA,IAClC;AACA,IAAM,WAAI,MAAM,OAAO;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,SAAiB;AACpB,IAAM,WAAI,KAAK,OAAO;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,SAAiB;AACpB,IAAM,WAAI,KAAK,OAAO;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAW,SAAiB,IAAkC;AAClE,SAAK,MAAM,OAAO;AAClB,QAAI;AACF,YAAM,SAAS,MAAM,GAAG;AACxB,WAAK,QAAQ,OAAO;AACpB,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,KAAK,OAAO;AACjB,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,SAAkB;AACrB,QAAI,KAAK,gBAAgB;AACvB,WAAK,eAAe,KAAK,WAAW,EAAE;AAAA,IACxC;AAAA,EACF;AACF;AAgCO,SAAS,eAAe,SAAyB;AACtD,QAAM,QAAQ;AAAA,IACZ;AAAA,IACAA,IAAG,KAAK,WAAW;AAAA,IACnB,KAAKA,IAAG,KAAK,QAAQ,OAAO,CAAC;AAAA,IAC7B;AAAA,IACA,GAAGA,IAAG,KAAK,SAAS,CAAC,IAAIA,IAAG,KAAK,QAAQ,MAAM,CAAC;AAAA,EAClD;AAEA,MAAI,QAAQ,eAAe;AACzB,UAAM,KAAK,GAAGA,IAAG,KAAK,aAAa,CAAC,IAAIA,IAAG,KAAK,QAAQ,aAAa,CAAC,EAAE;AAAA,EAC1E;AAEA,MAAI,QAAQ,WAAW;AACrB,UAAM,KAAK,GAAGA,IAAG,KAAK,iBAAiB,CAAC,IAAIA,IAAG,KAAK,QAAQ,SAAS,CAAC,EAAE;AAAA,EAC1E;AAEA,QAAM;AAAA,IACJ;AAAA,IACAA,IAAG,KAAK,aAAa;AAAA,IACrB,qBAAqBA,IAAG,OAAO,wBAAwB,CAAC;AAAA,IACxD,wBAAwBA,IAAG,KAAK,uBAAuB,CAAC;AAAA,IACxD;AAAA,EACF;AAEA,EAAM,aAAMA,IAAG,MAAM,6CAA6C,CAAC;AACnE,UAAQ,IAAI,MAAM,KAAK,IAAI,CAAC;AAG5B,MAAI,QAAQ,kBAAkB,QAAQ,QAAQ;AAC5C,IAAM;AAAA,MACJ,4EAA4EA,IAAG;AAAA,QAC7E,QAAQ;AAAA,MACV,CAAC;AAAA;AAAA;AAAA,MACDA,IAAG,MAAM,4BAAuB;AAAA,IAClC;AAAA,EACF;AAEA,MAAI,QAAQ,cAAc,QAAQ,WAAW,SAAS,GAAG;AAEvD,UAAM,SAAS,QAAQ,WAAW,CAAC,GAAG,KAAK,MAAM,cAAc,EAAE,CAAC;AAElE,UAAM,WAAW;AAAA,MACfA,IAAG,KAAK,uBAAuB;AAAA,MAC/B,GAAG,QAAQ,WAAW;AAAA,QACpB,CAAC,WACC,KAAKA,IAAG,KAAK,OAAO,IAAI,CAAC,IAAIA,IAAG,IAAI,OAAO,IAAI,CAAC,KAAK,OAAO,KAAK;AAAA,MACrE;AAAA,IACF;AAEA,QAAI,QAAQ;AAEV,YAAM,iBAAiB,QAAQ,kBAAkB;AACjD,eAAS;AAAA,QACP;AAAA,QACAA,IAAG,KAAK,mBAAmB;AAAA,QAC3B,KAAKA,IAAG,KAAK,MAAM,CAAC,IAAIA,IAAG,IAAI,KAAK,CAAC;AAAA,QACrCA,IAAG,IAAI,+EAA+E;AAAA,QACtF;AAAA,QACAA,IAAG,KAAK,qBAAqB;AAAA,QAC7B,KAAKA,IAAG,KAAK,UAAU,MAAM,EAAE,CAAC,IAAIA,IAAG,IAAI,KAAK,CAAC,mDAAmD,cAAc;AAAA,MACpH;AAGA,UAAI,QAAQ,gBAAgB;AAC1B,iBAAS;AAAA,UACP;AAAA,UACAA,IAAG,KAAK,iDAAiD;AAAA,UACzD,KAAKA,IAAG,KAAK,QAAQ,cAAc,CAAC,IAAIA,IAAG,IAAI,IAAI,CAAC,sBAAsB,QAAQ,MAAM;AAAA,UACxF,KAAKA,IAAG,KAAK,QAAQ,cAAc,CAAC,IAAIA,IAAG,IAAI,KAAK,CAAC;AAAA,QACvD;AAAA,MACF;AAAA,IACF;AAEA,IAAM,YAAK,SAAS,KAAK,IAAI,GAAG,qBAAqB;AAAA,EACvD;AAGA,MAAI,QAAQ,wBAAwB,QAAQ,qBAAqB,SAAS,GAAG;AAC3E,UAAM,cAAc;AAAA,MAClBA,IAAG,KAAK,mCAAmC;AAAA,MAC3C,GAAG,QAAQ,qBAAqB;AAAA,QAC9B,CAAC,WACC,KAAKA,IAAG,KAAK,OAAO,IAAI,CAAC,IAAIA,IAAG,IAAI,OAAO,IAAI,CAAC,KAAK,OAAO,KAAK;AAAA,MACrE;AAAA,MACA;AAAA,MACAA,IAAG;AAAA,QACD;AAAA,MACF;AAAA,MACAA,IAAG;AAAA,QACD;AAAA,MACF;AAAA,IACF;AAEA,IAAM;AAAA,MACJ,YAAY,KAAK,IAAI;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAGA,MACE,QAAQ,4BACR,QAAQ,yBAAyB,SAAS,GAC1C;AACA,UAAM,mBAAmB,QAAQ,uBAAuB,UAAU;AAClE,UAAM,mBAAmB;AAAA,MACvBA,IAAG,KAAK,4BAA4B,gBAAgB,kBAAkB;AAAA,MACtE,GAAG,QAAQ,yBAAyB;AAAA,QAClC,CAAC,WACC,KAAKA,IAAG,KAAK,OAAO,IAAI,CAAC,IAAIA,IAAG,IAAI,OAAO,IAAI,CAAC,KAAK,OAAO,KAAK;AAAA,MACrE;AAAA,MACA;AAAA,MACAA,IAAG;AAAA,QACD;AAAA,MACF;AAAA,MACAA,IAAG,IAAI,iDAAiD;AAAA,IAC1D;AAEA,QAAI,QAAQ,sBAAsB;AAChC,uBAAiB;AAAA,QACf;AAAA,QACAA,IAAG,IAAI,gEAAgE;AAAA,MACzE;AAAA,IACF;AAEA,IAAM;AAAA,MACJ,iBAAiB,KAAK,IAAI;AAAA,MAC1B;AAAA,IACF;AAEA,QAAI,QAAQ,sBAAsB;AAChC,cAAQ;AAAA,QACN;AAAA,EAAKA,IAAG,IAAI,MAAM,CAAC,IAAIA,IAAG,OAAO,+BAA+B,QAAQ,oBAAoB,EAAE,CAAC,IAAIA,IAAG;AAAA,UACpG;AAAA,QACF,CAAC;AAAA;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAIA,MACE,QAAQ,wBACR,CAAC,QAAQ;AAAA,EACT,CAAC,QAAQ,mBACR,CAAC,QAAQ,cAAc,QAAQ,WAAW,WAAW,OACrD,CAAC,QAAQ,4BACR,QAAQ,yBAAyB,WAAW,IAC9C;AACA,UAAM,gBAAgB;AAAA,MACpBA,IAAG,KAAK,0BAA0B;AAAA,MAClC,KAAKA,IAAG,KAAK,QAAQ,oBAAoB,CAAC,IAAIA,IAAG,IAAI,OAAO,CAAC,OAAO,QAAQ,MAAM;AAAA,MAClF;AAAA,MACAA,IAAG;AAAA,QACD;AAAA,MACF;AAAA,MACAA,IAAG,IAAI,iDAAiD;AAAA,IAC1D;AAEA,IAAM,YAAK,cAAc,KAAK,IAAI,GAAG,oBAAoB;AAAA,EAC3D;AACF;AAmCO,SAAS,cAAcC,SAAuB;AACnD,EAAM,aAAMD,IAAG,KAAK,4BAA4B,CAAC;AAEjD,QAAM,YAAY;AAAA,IAChB,GAAGA,IAAG,KAAK,cAAc,CAAC,IAAIA,IAAG,KAAKC,QAAO,gBAAgB,CAAC;AAAA,IAC9D,GAAGD,IAAG,KAAK,SAAS,CAAC,IAAIA,IAAG,KAAKC,QAAO,MAAM,CAAC;AAAA,EACjD;AAEA,MAAIA,QAAO,QAAQ,SAAS,GAAG;AAC7B,UAAM,gBAAgBA,QAAO,QAAQ,IAAI,CAAC,MAAM;AAC9C,YAAM,aACJ,EAAE,WAAW,aAAa,WAAM,EAAE,WAAW,YAAY,WAAM;AACjE,YAAM,cACJ,EAAE,WAAW,aACTD,IAAG,QACH,EAAE,WAAW,YACXA,IAAG,SACHA,IAAG;AAEX,UAAI,aAAa,OAAO,EAAE,MAAM,IAAI,YAAY,GAAG,UAAU,IAAI,EAAE,MAAM,EAAE,CAAC;AAG5E,UAAI,EAAE,gBAAgB;AACpB,cAAM,qBAAqB,EAAE,mBAAmB,YAAY,WAAM;AAClE,cAAM,gBACJ,EAAE,mBAAmB,YAAYA,IAAG,QAAQA,IAAG;AACjD,sBAAc;AAAA,QAAWA,IAAG,IAAI,YAAY,CAAC,IAAI,EAAE,cAAc,IAAI,cAAc,kBAAkB,CAAC;AAAA,MACxG;AAEA,aAAO;AAAA,IACT,CAAC;AACD,cAAU,KAAK,GAAGA,IAAG,KAAK,UAAU,CAAC;AAAA,EAAK,cAAc,KAAK,IAAI,CAAC,EAAE;AAAA,EACtE;AAEA,EAAM,YAAK,UAAU,KAAK,IAAI,GAAG,eAAe;AAGhD,QAAM,eAAe,CAAC;AACtB,eAAa,KAAK,KAAKA,IAAG,MAAM,QAAG,CAAC,kBAAkBA,IAAG,IAAI,WAAW,CAAC,EAAE;AAE3E,MAAIC,QAAO,UAAU,WAAW;AAC9B,iBAAa;AAAA,MACX,KAAKD,IAAG,MAAM,QAAG,CAAC,mBAAmBA,IAAG,IAAI,iBAAiB,CAAC;AAAA,IAChE;AAAA,EACF,OAAO;AACL,iBAAa;AAAA,MACX,KAAKA,IAAG,IAAI,QAAG,CAAC,mBAAmBA,IAAG,IAAI,uCAAuC,CAAC;AAAA,IACpF;AAAA,EACF;AAEA,MACEC,QAAO,UAAU,mBACjBA,QAAO,UAAU,kBAAkB,GACnC;AACA,iBAAa;AAAA,MACX,KAAKD,IAAG,MAAM,QAAG,CAAC,8BAA8BA,IAAG,IAAI,aAAa,CAAC;AAAA,IACvE;AAAA,EACF,OAAO;AACL,iBAAa;AAAA,MACX,KAAKA,IAAG,IAAI,QAAG,CAAC,8BAA8BA,IAAG,IAAI,uCAAuC,CAAC;AAAA,IAC/F;AAAA,EACF;AAGA,MAAIC,QAAO,UAAU,kBAAkB;AACrC,UAAM,iBACJ;AAAA,MACE,SAAS;AAAA,MACT,UAAU;AAAA,MACV,UAAU;AAAA,MACV,WAAW;AAAA,MACX,SAAS;AAAA,MACT,YAAY;AAAA,IACd,EAAEA,QAAO,UAAU,oBAAoB,QAAQ,KAAK;AACtD,iBAAa;AAAA,MACX,KAAKD,IAAG,MAAM,QAAG,CAAC,oBAAoBA,IAAG,IAAI,IAAI,cAAc,aAAa,CAAC;AAAA,IAC/E;AAAA,EACF,OAAO;AACL,iBAAa;AAAA,MACX,KAAKA,IAAG,IAAI,QAAG,CAAC,oBAAoBA,IAAG,IAAI,uCAAuC,CAAC;AAAA,IACrF;AAAA,EACF;AAGA,MAAIC,QAAO,UAAU,sBAAsB;AACzC,UAAM,WAAWA,QAAO,SAAS,eAAe,UAAU;AAC1D,UAAM,mBAAmBA,QAAO,SAAS,eACrCA,QAAO,SAAS,mBACdD,IAAG,MAAM,eAAU,IACnBA,IAAG,OAAO,gBAAW,IACvB;AACJ,UAAM,gBAAgBC,QAAO,SAAS,eAClC,GAAG,QAAQ,aAAa,gBAAgB,KACxC,GAAG,QAAQ;AACf,iBAAa;AAAA,MACX,KAAKD,IAAG,MAAM,QAAG,CAAC,2BAA2BA,IAAG,IAAI,IAAI,aAAa,GAAG,CAAC;AAAA,IAC3E;AACA,iBAAa,KAAK,SAASA,IAAG,KAAKC,QAAO,SAAS,oBAAoB,CAAC,EAAE;AAAA,EAC5E,OAAO;AACL,iBAAa;AAAA,MACX,KAAKD,IAAG,IAAI,QAAG,CAAC,2BAA2BA,IAAG,IAAI,uCAAuC,CAAC;AAAA,IAC5F;AAAA,EACF;AAEA,eAAa;AAAA,IACX,KAAKA,IAAG,MAAM,QAAG,CAAC,sBAAsBA,IAAG,IAAI,uBAAuB,CAAC;AAAA,EACzE;AAEA,EAAM,YAAK,aAAa,KAAK,IAAI,GAAG,UAAU;AAG9C,QAAM,gBAAgB,CAAC;AAEvB,MAAIC,QAAO,UAAU,SAAS;AAC5B,kBAAc;AAAA,MACZ,KAAKD,IAAG,MAAM,QAAG,CAAC,cAAcA,IAAG,KAAKC,QAAO,UAAU,OAAO,CAAC;AAAA,IACnE;AAAA,EACF;AAEA,MAAIA,QAAO,UAAU,eAAe;AAClC,kBAAc;AAAA,MACZ,KAAKD,IAAG,MAAM,QAAG,CAAC,uBAAuBA,IAAG,KAAKC,QAAO,UAAU,aAAa,CAAC;AAAA,IAClF;AAAA,EACF;AAEA,MAAIA,QAAO,UAAU,WAAW;AAC9B,kBAAc;AAAA,MACZ,KAAKD,IAAG,MAAM,QAAG,CAAC,oBAAoBA,IAAG,KAAKC,QAAO,UAAU,SAAS,CAAC;AAAA,IAC3E;AAAA,EACF;AAEA,MAAIA,QAAO,UAAU,iBAAiB;AACpC,kBAAc;AAAA,MACZ,KAAKD,IAAG,MAAM,QAAG,CAAC,sBAAsBA,IAAG;AAAA,QACzC,GAAGC,QAAO,UAAU,eAAe;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAIA,QAAO,UAAU,WAAW;AAC9B,kBAAc;AAAA,MACZ,KAAKD,IAAG,MAAM,QAAG,CAAC,gBAAgBA,IAAG,KAAK,GAAGC,QAAO,UAAU,SAAS,aAAa,CAAC;AAAA,IACvF;AAAA,EACF;AAEA,MAAIA,QAAO,UAAU,YAAY;AAC/B,kBAAc;AAAA,MACZ,KAAKD,IAAG,MAAM,QAAG,CAAC,0BAA0BA,IAAG,KAAKC,QAAO,UAAU,UAAU,CAAC;AAAA,IAClF;AAAA,EACF;AAEA,EAAM,YAAK,cAAc,KAAK,IAAI,GAAG,WAAW;AAGhD,QAAM,oBAAoBA,QAAO,QAAQ;AAAA,IACvC,CAAC,MACE,EAAE,WAAW,aAAa,EAAE,cAC5B,EAAE,kBAAkB,EAAE,mBAAmB;AAAA,EAC9C;AACA,MAAI,kBAAkB,SAAS,GAAG;AAChC,eAAW,UAAU,mBAAmB;AACtC,YAAM,WAAW,CAAC;AAGlB,UACE,OAAO,WAAW,aAClB,OAAO,cACP,OAAO,WAAW,SAAS,GAC3B;AAEA,cAAM,iBAAiB,OAAO,kBAAkB,OAAO;AACvD,iBAAS;AAAA,UACPD,IAAG,KAAK,uBAAuB;AAAA,UAC/B,GAAG,OAAO,WAAW;AAAA,YACnB,CAAC,UACC,KAAKA,IAAG,KAAK,GAAG,KAAK,eAAe,OAAO,MAAM,EAAE,CAAC,IAAIA,IAAG,IAAI,OAAO,CAAC,KAAK,KAAK;AAAA,UACrF;AAAA,UACA;AAAA,UACAA,IAAG,KAAK,mBAAmB;AAAA,UAC3B,KAAKA,IAAG,KAAK,OAAO,MAAM,CAAC,IAAIA,IAAG,IAAI,KAAK,CAAC;AAAA,UAC5CA,IAAG,IAAI,+EAA+E;AAAA,UACtF;AAAA,UACAA,IAAG,KAAK,qBAAqB;AAAA,UAC7B,KAAKA,IAAG,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC,IAAIA,IAAG,IAAI,KAAK,CAAC,mDAAmD,cAAc;AAAA,QAC3H;AAAA,MACF;AAGA,UAAI,OAAO,kBAAkB,OAAO,mBAAmB,WAAW;AAChE,YAAI,SAAS,SAAS,GAAG;AACvB,mBAAS,KAAK,EAAE;AAAA,QAClB;AACA,iBAAS;AAAA,UACPA,IAAG,KAAK,iDAAiD;AAAA,UACzD,KAAKA,IAAG,KAAK,OAAO,cAAc,CAAC,IAAIA,IAAG,IAAI,IAAI,CAAC,sBAAsBC,QAAO,MAAM;AAAA,UACtF,KAAKD,IAAG,KAAK,OAAO,cAAc,CAAC,IAAIA,IAAG,IAAI,KAAK,CAAC;AAAA,QACtD;AAAA,MACF;AAEA,UAAI,SAAS,SAAS,GAAG;AACvB,QAAM,YAAK,SAAS,KAAK,IAAI,GAAG,mBAAmB,OAAO,MAAM,EAAE;AAAA,MACpE;AAAA,IACF;AAGA,UAAM,gBAAgB,kBAAkB,CAAC,EAAE;AAC3C,YAAQ;AAAA,MACN;AAAA,EAAKA,IAAG,IAAI,MAAM,CAAC,IAAIA,IAAG,OAAO,+BAA+B,aAAa,EAAE,CAAC,IAAIA,IAAG;AAAA,QACrF;AAAA,MACF,CAAC;AAAA;AAAA,IACH;AAAA,EACF;AAEA,UAAQ,IAAI;AAAA,EAAKA,IAAG,KAAK,YAAY,CAAC,IAAIA,IAAG,KAAK,uBAAuB,CAAC,EAAE;AAC5E,UAAQ,IAAI,GAAGA,IAAG,KAAK,OAAO,CAAC,IAAIA,IAAG,KAAK,wBAAwB,CAAC;AAAA,CAAI;AAC1E;AAoBO,SAAS,eAAe,SAA+B;AAC5D,UAAQ,IAAIA,IAAG,OAAO,oDAAoD,CAAC;AAG3E,QAAM,UAAU,QAAQ;AACxB,QAAM,eAAyB,CAAC;AAEhC,MAAI,QAAQ,UAAU,QAAQ,SAAS,GAAG;AACxC,iBAAa,KAAK,KAAKA,IAAG,MAAM,GAAG,CAAC,IAAI,QAAQ,MAAM,YAAY;AAAA,EACpE;AACA,MAAI,QAAQ,UAAU,QAAQ,SAAS,GAAG;AACxC,iBAAa,KAAK,KAAKA,IAAG,OAAO,GAAG,CAAC,IAAI,QAAQ,MAAM,YAAY;AAAA,EACrE;AACA,MAAI,QAAQ,UAAU,QAAQ,SAAS,GAAG;AACxC,iBAAa,KAAK,KAAKA,IAAG,IAAI,GAAG,CAAC,IAAI,QAAQ,MAAM,aAAa;AAAA,EACnE;AACA,MAAI,QAAQ,QAAQ,QAAQ,OAAO,GAAG;AACpC,iBAAa,KAAK,KAAKA,IAAG,IAAI,GAAG,CAAC,IAAI,QAAQ,IAAI,YAAY;AAAA,EAChE;AACA,MAAI,QAAQ,WAAW,QAAQ,UAAU,GAAG;AAC1C,iBAAa,KAAK,KAAKA,IAAG,QAAQ,IAAI,CAAC,IAAI,QAAQ,OAAO,aAAa;AAAA,EACzE;AAEA,MAAI,aAAa,SAAS,GAAG;AAC3B,IAAM,YAAK,aAAa,KAAK,IAAI,GAAG,kBAAkB;AAAA,EACxD,OAAO;AACL,IAAM,YAAK,uBAAuB,kBAAkB;AAAA,EACtD;AAGA,MAAI,QAAQ,cAAc;AACxB,IAAM,YAAK,QAAQ,cAAc,wBAAwB;AAAA,EAC3D;AAEA,UAAQ,IAAIA,IAAG,OAAO,gDAAgD,CAAC;AACzE;;;AHpiBA,eAAsB,WAAW,SAA2C;AAC1E,EAAAE,OAAMC,IAAG,KAAK,qCAAqC,CAAC;AAEpD,QAAM,WAAW,IAAI,mBAAmB;AAGxC,QAAM,WAAW,MAAM,SAAS;AAAA,IAC9B;AAAA,IACA,YAAY,uBAAuB;AAAA,EACrC;AAGA,QAAM,SAAS,QAAQ,UAAW,MAAM,aAAa;AAGrD,QAAM,WAAW,MAAM,uBAAuB,SAAS,WAAW,MAAM;AACxE,MAAI,CAAC,UAAU;AACb,aAAS,KAAK;AACd,IAAAC,KAAI;AAAA,MACF,yCAAyCD,IAAG,KAAK,SAAS,SAAS,CAAC,cAAcA,IAAG,KAAK,MAAM,CAAC;AAAA,IACnG;AACA,YAAQ;AAAA,MACN;AAAA,MAASA,IAAG,KAAK,kBAAkB,CAAC;AAAA;AAAA,IACtC;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,WAAW;AACjB,QAAME,OAAM,IAAI,UAAU,EAAE,QAAQ,YAAY,CAAC;AAEjD,MAAIC,cAAa;AACjB,MAAI;AACF,UAAMD,KAAI,KAAK,IAAI,eAAe,EAAE,UAAU,SAAS,CAAC,CAAC;AACzD,IAAAC,cAAa;AAAA,EACf,SAAS,OAAO;AACd,QACE,SACA,OAAO,UAAU,YACjB,UAAU,SACV,MAAM,SAAS,gBACf;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAEA,MAAI,CAACA,aAAY;AACf,aAAS,KAAK;AACd,IAAAF,KAAI,KAAK,YAAYD,IAAG,KAAK,QAAQ,CAAC,iBAAiB;AACvD,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,WAAS,KAAK,mBAAmBA,IAAG,KAAK,QAAQ,CAAC,EAAE;AAGpD,MAAI,CAAC,QAAQ,OAAO;AAClB,aAAS,KAAK;AACd,UAAM,iBAAiB,MAAM,QAAQ;AAAA,MACnC,SAAS,mBAAmBA,IAAG,KAAK,QAAQ,CAAC;AAAA,MAC7C,cAAc;AAAA,IAChB,CAAC;AAED,QAAI,SAAS,cAAc,KAAK,CAAC,gBAAgB;AAC/C,MAAAI,OAAM,kBAAkB;AACxB,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAGA,QAAM,cAAc,SAAS,SAAS,OAAO;AAC7C,QAAM,SAAS,2BAA2B,WAAW;AAGrD,QAAM,iBACJ,CAAC,eACA,YAAY,mBAA2C;AAC1D,QAAM,gBAAgB,aAAa;AAGnC,QAAM,iBAAiB,aAAa;AAKpC,QAAM,SAAS,QAAQ,iCAAiC,YAAY;AAClE,UAAM,EAAE,qBAAqB,IAAI,MAAM,OAAO,qBAAqB;AAEnE,UAAMF,KAAI;AAAA,MACR,IAAI,qBAAqB;AAAA,QACvB,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,gBAAgB,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,MAChD,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,WAAS,KAAK;AAGd,EAAAE,OAAMJ,IAAG,MAAM,0DAAqD,CAAC;AAErE,UAAQ,IAAI;AAAA,EAAKA,IAAG,KAAK,sBAAsB,CAAC,EAAE;AAClD,UAAQ;AAAA,IACN,KAAKA,IAAG,MAAM,QAAG,CAAC;AAAA,EACpB;AACA,UAAQ,IAAI,KAAKA,IAAG,MAAM,QAAG,CAAC,2CAA2C;AAEzE,MAAI,gBAAgB;AAClB,YAAQ,IAAI,KAAKA,IAAG,MAAM,QAAG,CAAC,wBAAwB;AAAA,EACxD;AAEA,MAAI,eAAe,iBAAiB;AAClC,YAAQ;AAAA,MACN,KAAKA,IAAG,MAAM,QAAG,CAAC;AAAA,IACpB;AAAA,EACF;AAEA,MAAI,eAAe,SAAS;AAC1B,YAAQ,IAAI,KAAKA,IAAG,MAAM,QAAG,CAAC,6BAA6B;AAAA,EAC7D;AAEA,MAAI,gBAAgB,SAAS;AAC3B,YAAQ,IAAI,KAAKA,IAAG,MAAM,QAAG,CAAC,8BAA8B;AAAA,EAC9D;AAEA,UAAQ;AAAA,IACN;AAAA,EAAKA,IAAG,IAAI,+EAA+E,CAAC;AAAA;AAAA,EAC9F;AACF;AAmBA,SAAS,2BACP,aACgB;AAChB,QAAM,aAAgC,CAAC;AAGvC,aAAW,KAAK;AAAA,IACd,QAAQ;AAAA,IACR,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,UAAU;AAAA,EACZ,CAAC;AAGD,aAAW,KAAK;AAAA,IACd,QAAQ;AAAA,IACR,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,UAAU;AAAA,EACZ,CAAC;AAGD,QAAM,iBAAiB,CAAC,eAAe,YAAY,mBAAmB;AACtE,MAAI,gBAAgB;AAClB,eAAW,KAAK;AAAA,MACd,QAAQ;AAAA,MACR,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAGA,QAAM,gBAAgB,aAAa;AAGnC,MAAI,eAAe,iBAAiB;AAClC,eAAW,KAAK;AAAA,MACd,QAAQ;AAAA,MACR,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,UAAU;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAGA,MAAI,eAAe,SAAS;AAC1B,eAAW,KAAK;AAAA,MACd,QAAQ;AAAA,MACR,QAAQ,CAAC,oBAAoB,yBAAyB;AAAA,MACtD,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAGA,MAAI,eAAe,SAAS;AAC1B,eAAW,KAAK;AAAA,MACd,QAAQ;AAAA,MACR,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAGA,QAAM,iBAAiB,aAAa;AAGpC,MAAI,gBAAgB,SAAS;AAC3B,eAAW,KAAK;AAAA,MACd,QAAQ;AAAA,MACR,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,EACb;AACF;;;AIvSA;AAAA,YAAYK,YAAW;AACvB,YAAYC,aAAY;AACxB,OAAOC,SAAQ;;;ACFf;AAAA,YAAYC,WAAS;AACrB,YAAYC,aAAY;;;ACDxB;AAAA,YAAY,SAAS;AAoBrB,eAAe,YAAY,WAAqC;AAC9D,MAAI;AACF,UAAM,EAAE,gBAAAC,iBAAgB,sBAAAC,sBAAqB,IAAI,MAAM,OACrD,0BACF;AACA,UAAMC,YAAW,IAAIF,gBAAe;AAAA,MAClC,QAAQ,QAAQ,IAAI,cAAc;AAAA,IACpC,CAAC;AAED,UAAME,UAAS,KAAK,IAAID,sBAAqB,EAAE,WAAW,UAAU,CAAC,CAAC;AACtE,WAAO;AAAA,EACT,SAAS,OAAY;AACnB,QAAI,MAAM,SAAS,6BAA6B;AAC9C,aAAO;AAAA,IACT;AACA,YAAQ,MAAM,+CAA+C,KAAK;AAClE,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,qBACpB,SACyB;AAEzB,QAAM,YAAY;AAClB,QAAM,SAAS,MAAM,YAAY,SAAS;AAI1C,QAAM,eAAe,SACjB,IAAQ,aAAS;AAAA,IACf;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,MACT,UAAU;AAAA,MACV,YAAY;AAAA,QACV,EAAE,MAAM,aAAa,MAAM,IAAI;AAAA,QAC/B,EAAE,MAAM,UAAU,MAAM,IAAI;AAAA,QAC5B,EAAE,MAAM,aAAa,MAAM,IAAI;AAAA,MACjC;AAAA,MACA,wBAAwB;AAAA,QACtB;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,UACT,UAAU;AAAA,UACV,gBAAgB;AAAA,QAClB;AAAA,MACF;AAAA,MACA,KAAK;AAAA,QACH,SAAS;AAAA,QACT,eAAe;AAAA,MACjB;AAAA,MACA,MAAM;AAAA,QACJ,WAAW;AAAA,MACb;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA;AAAA,IACV;AAAA,EACF,IACA,IAAQ,aAAS,MAAM,WAAW;AAAA,IAChC,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YAAY;AAAA,MACV,EAAE,MAAM,aAAa,MAAM,IAAI;AAAA,MAC/B,EAAE,MAAM,UAAU,MAAM,IAAI;AAAA,MAC5B,EAAE,MAAM,aAAa,MAAM,IAAI;AAAA,IACjC;AAAA,IACA,wBAAwB;AAAA,MACtB;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,QACT,UAAU;AAAA,QACV,gBAAgB;AAAA,MAClB;AAAA,IACF;AAAA,IACA,KAAK;AAAA,MACH,SAAS;AAAA,MACT,eAAe;AAAA,IACjB;AAAA,IACA,MAAM;AAAA,MACJ,WAAW;AAAA,IACb;AAAA,EACF,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,EACF;AACF;;;ACnHA;AAAA,YAAYE,UAAS;AACrB,YAAY,YAAY;AA2BxB,eAAsB,2BACpBC,SAC+B;AAE/B,QAAM,eAAeA,QAAO,YAAY,MAAM,CAAC,QAAQ,IAAI,MAAM,GAAG,EAAE,IAAI,CAAE;AAG5E,QAAM,OAAO,IAAQ,gBAAW,UAAU,2BAA2B;AAAA,IACnE,MAAM;AAAA,IACN,aAAa;AAAA,IACb;AAAA,IACA,cAAc,KAAK,UAAU;AAAA,MAC3B,QAAQ,CAAC,SAAS;AAAA;AAAA;AAAA,IAGpB,CAAC;AAAA,IACD,MAAM;AAAA,MACJ,WAAW;AAAA,IACb;AAAA,EACF,CAAC;AAGD,MAAQ,SAAI,YAAY,mCAAmC;AAAA,IACzD,UAAUA,QAAO;AAAA,IACjB,QACG,WAAI,CAACA,QAAO,UAAU,KAAK,GAAG,CAAC,EAC/B;AAAA,MAAM,CAAC,CAAC,UAAU,OAAO,MACxB,KAAK,UAAU;AAAA,QACb,SAAS;AAAA,QACT,WAAW;AAAA,UACT;AAAA,YACE,QAAQ;AAAA,YACR,WAAW;AAAA,cACT,SAAS;AAAA,YACX;AAAA,YACA,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,WAAW;AAAA,cACT,WAAW;AAAA,gBACT,iBAAiB;AAAA,cACnB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACJ,CAAC;AAGD,QAAM,SAAS,IAAQ,gBAAW,YAAY,6BAA6B;AAAA,IACzE,MAAM,KAAK;AAAA,IACX;AAAA,IACA,KAAKA,QAAO;AAAA,EACd,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;;;ACvFA;AAAA,YAAYC,UAAS;AACrB,YAAYC,aAAY;AAiBxB,eAAe,WAAW,UAAoC;AAC5D,MAAI;AACF,UAAM,EAAE,WAAAC,YAAW,gBAAAC,gBAAe,IAAI,MAAM,OAAO,qBAAqB;AAExE,UAAMC,OAAM,IAAIF,WAAU;AAAA,MACxB,QAAQ,QAAQ,IAAI,cAAc;AAAA,IACpC,CAAC;AAED,UAAME,KAAI,KAAK,IAAID,gBAAe,EAAE,UAAU,SAAS,CAAC,CAAC;AACzD,WAAO;AAAA,EACT,SAAS,OAAY;AACnB,QAAI,MAAM,SAAS,yBAAyB;AAC1C,aAAO;AAAA,IACT;AACA,YAAQ,MAAM,yCAAyC,KAAK;AAC5D,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,cACpBE,SACuB;AAEvB,MAAI;AAEJ,MAAIA,QAAO,aAAa,YAAYA,QAAO,cAAc;AACvD,uBAA0B;AAAA;AAAA;AAAA;AAAA;AAAA,0BAKJA,QAAO,aAAa,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA,+BAKlBA,QAAO,cAAc,8BAA8BA,QAAO,cAAc;AAAA;AAAA;AAAA,+BAGxEA,QAAO,cAAc,iBAAiBA,QAAO,cAAc,YAAYA,QAAO,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA,EAK5H,WAAWA,QAAO,aAAa,OAAO;AAEpC,uBAA0B,eAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAS/B;AAAA,EACJ,OAAO;AAEL,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD;AAGA,QAAM,WAAW;AACjB,QAAM,SAAS,MAAM,WAAW,QAAQ;AAExC,QAAM,OAAO,SACT,IAAQ,SAAI;AAAA,IACV;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN;AAAA,MACA,MAAM;AAAA,QACJ,WAAW;AAAA,QACX,UAAUA,QAAO;AAAA,MACnB;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA;AAAA,IACV;AAAA,EACF,IACA,IAAQ,SAAI,KAAK,UAAU;AAAA,IACzB,MAAM;AAAA,IACN;AAAA,IACA,MAAM;AAAA,MACJ,WAAW;AAAA,MACX,UAAUA,QAAO;AAAA,IACnB;AAAA,EACF,CAAC;AAGL,QAAM,aAAoB,CAAC;AAG3B,aAAW,KAAK;AAAA,IACd,QAAQ;AAAA,IACR,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,UAAU;AAAA,EACZ,CAAC;AAGD,MAAIA,QAAO,YAAY,mBAAmB,OAAO;AAC/C,eAAW,KAAK;AAAA,MACd,QAAQ;AAAA,MACR,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAGA,MAAIA,QAAO,YAAY,eAAe,iBAAiB;AACrD,eAAW,KAAK;AAAA,MACd,QAAQ;AAAA,MACR,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,UAAU;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAGA,MAAIA,QAAO,YAAY,eAAe,SAAS;AAC7C,eAAW,KAAK;AAAA,MACd,QAAQ;AAAA,MACR,QAAQ,CAAC,oBAAoB,yBAAyB;AAAA,MACtD,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAGA,MAAIA,QAAO,YAAY,eAAe,SAAS;AAC7C,eAAW,KAAK;AAAA,MACd,QAAQ;AAAA,MACR,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAGA,MAAIA,QAAO,YAAY,gBAAgB,SAAS;AAC9C,eAAW,KAAK;AAAA,MACd,QAAQ;AAAA,MACR,QAAQ;AAAA;AAAA,QAEN;AAAA,QACA;AAAA;AAAA,QAEA;AAAA,QACA;AAAA;AAAA,QAEA;AAAA,QACA;AAAA;AAAA,QAEA;AAAA,QACA;AAAA,MACF;AAAA,MACA,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAGA,MAAQ,SAAI,WAAW,sBAAsB;AAAA,IAC3C,MAAM,KAAK;AAAA,IACX,QAAQ,KAAK,UAAU;AAAA,MACrB,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH,CAAC;AAED,SAAO;AACT;;;ACtNA;AAAA,SAAS,mBAAmB;AAC5B,SAAS,cAAAC,aAAY,iBAAiB;AACtC,SAAS,cAAc;AACvB,SAAS,SAAS,QAAAC,aAAY;AAC9B,SAAS,iBAAAC,sBAAqB;AAC9B,YAAYC,UAAS;AACrB,YAAYC,aAAY;AACxB,SAAS,aAAa;AAMtB,SAAS,iBAAyB;AAChC,QAAM,cAAcF,eAAc,YAAY,GAAG;AACjD,MAAI,MAAM,QAAQ,WAAW;AAG7B,SAAO,QAAQ,QAAQ,GAAG,GAAG;AAC3B,QAAIF,YAAWC,MAAK,KAAK,cAAc,CAAC,GAAG;AACzC,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,GAAG;AAAA,EACnB;AAEA,QAAM,IAAI,MAAM,6BAA6B;AAC/C;AAwBA,eAAe,qBAAqB,cAAwC;AAC1E,MAAI;AACF,UAAM,EAAE,cAAAI,eAAc,mBAAmB,IAAI,MAAM,OACjD,wBACF;AACA,UAAMC,UAAS,IAAID,cAAa;AAAA,MAC9B,QAAQ,QAAQ,IAAI,cAAc;AAAA,IACpC,CAAC;AAED,UAAMC,QAAO,KAAK,IAAI,mBAAmB,EAAE,cAAc,aAAa,CAAC,CAAC;AACxE,WAAO;AAAA,EACT,SAAS,OAAY;AACnB,QAAI,MAAM,SAAS,6BAA6B;AAC9C,aAAO;AAAA,IACT;AACA,YAAQ,MAAM,gDAAgD,KAAK;AACnE,WAAO;AAAA,EACT;AACF;AAKA,eAAe,uBACb,cACA,UACwB;AACxB,MAAI;AACF,UAAM,EAAE,cAAAD,eAAc,+BAA+B,IAAI,MAAM,OAC7D,wBACF;AACA,UAAMC,UAAS,IAAID,cAAa;AAAA,MAC9B,QAAQ,QAAQ,IAAI,cAAc;AAAA,IACpC,CAAC;AAED,UAAM,WAAW,MAAMC,QAAO;AAAA,MAC5B,IAAI,+BAA+B;AAAA,QACjC,cAAc;AAAA,QACd,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH;AAGA,WAAO,SAAS,sBAAsB,CAAC,GAAG,QAAQ;AAAA,EACpD,SAAS,OAAY;AACnB,YAAQ,MAAM,uCAAuC,KAAK;AAC1D,WAAO;AAAA,EACT;AACF;AAQA,eAAe,cAAc,cAAuC;AAClE,QAAM,cAAc,eAAe;AAGnC,QAAM,iBAAiBL,MAAK,aAAa,QAAQ,UAAU,YAAY;AACvE,QAAM,mBAAmBA,MAAK,gBAAgB,UAAU;AAExD,MAAID,YAAW,gBAAgB,GAAG;AAEhC,WAAO;AAAA,EACT;AAGA,QAAM,aAAaC,MAAK,aAAa,UAAU,YAAY;AAC3D,QAAM,qBAAqBA,MAAK,YAAY,UAAU;AAEtD,MAAID,YAAW,kBAAkB,GAAG;AAElC,WAAO;AAAA,EACT;AAGA,QAAM,aAAaC,MAAK,YAAY,UAAU;AAE9C,MAAI,CAACD,YAAW,UAAU,GAAG;AAC3B,UAAM,IAAI;AAAA,MACR,4BAA4B,UAAU;AAAA;AAAA;AAAA,IAGxC;AAAA,EACF;AAEA,QAAM,UAAU,YAAY,CAAC,EAAE,SAAS,KAAK;AAC7C,QAAM,SAASC,MAAK,OAAO,GAAG,gBAAgB,OAAO,EAAE;AAEvD,MAAI,CAACD,YAAW,MAAM,GAAG;AACvB,cAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AAAA,EACvC;AAGA,QAAM,MAAM;AAAA,IACV,aAAa,CAAC,UAAU;AAAA,IACxB,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAASC,MAAK,QAAQ,WAAW;AAAA,IACjC,UAAU,CAAC,YAAY;AAAA;AAAA,IACvB,QAAQ;AAAA,IACR,WAAW;AAAA,EACb,CAAC;AAED,SAAO;AACT;AAWA,eAAsB,sBACpBM,SAC0B;AAE1B,QAAM,qBAAqB,MAAM,cAAc,iBAAiB;AAGhE,QAAM,aAAa,IAAQ,SAAI,KAAK,2BAA2B;AAAA,IAC7D,kBAAkB,KAAK,UAAU;AAAA,MAC/B,SAAS;AAAA,MACT,WAAW;AAAA,QACT;AAAA,UACE,QAAQ;AAAA,UACR,WAAW,EAAE,SAAS,uBAAuB;AAAA,UAC7C,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF,CAAC;AAAA,IACD,MAAM;AAAA,MACJ,WAAW;AAAA,IACb;AAAA,EACF,CAAC;AAGD,MAAQ,SAAI,qBAAqB,sCAAsC;AAAA,IACrE,MAAM,WAAW;AAAA,IACjB,WACE;AAAA,EACJ,CAAC;AAGD,MAAQ,SAAI,WAAW,6BAA6B;AAAA,IAClD,MAAM,WAAW;AAAA,IACjB,QACG,YAAI,CAACA,QAAO,WAAWA,QAAO,QAAQ,CAAC,EACvC;AAAA,MAAM,CAAC,CAAC,WAAW,QAAQ,MAC1B,KAAK,UAAU;AAAA,QACb,SAAS;AAAA,QACT,WAAW;AAAA,UACT;AAAA;AAAA,YAEE,QAAQ;AAAA,YACR,QAAQ;AAAA,cACN;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,YACA,UAAU;AAAA,cACR,8BAA8B,SAAS;AAAA,cACvC,8BAA8B,SAAS;AAAA,YACzC;AAAA,UACF;AAAA,UACA;AAAA;AAAA,YAEE,QAAQ;AAAA,YACR,QAAQ;AAAA,cACN;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,YACA,UAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACJ,CAAC;AAGD,QAAM,eAAe;AACrB,QAAM,SAAS,MAAM,qBAAqB,YAAY;AAGtD,QAAM,iBAAiB,SACnB,IAAQ,YAAO;AAAA,IACb;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,MACT,MAAM,WAAW;AAAA,MACjB,MAAM,IAAW,cAAM,YAAY,kBAAkB;AAAA,MACrD,SAAS;AAAA;AAAA,MACT,YAAY;AAAA,MACZ,aAAa;AAAA,QACX,WAAW;AAAA,UACT,YAAYA,QAAO;AAAA,UACnB,gBAAgBA,QAAO;AAAA,QACzB;AAAA,MACF;AAAA,MACA,MAAM;AAAA,QACJ,WAAW;AAAA,QACX,aACE;AAAA,MACJ;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA;AAAA,IACV;AAAA,EACF,IACA,IAAQ,YAAO,SAAS,cAAc;AAAA,IACpC,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,IACT,MAAM,WAAW;AAAA,IACjB,MAAM,IAAW,cAAM,YAAY,kBAAkB;AAAA,IACrD,SAAS;AAAA;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,MACX,WAAW;AAAA,QACT,YAAYA,QAAO;AAAA,QACnB,gBAAgBA,QAAO;AAAA,MACzB;AAAA,IACF;AAAA,IACA,MAAM;AAAA,MACJ,WAAW;AAAA,MACX,aACE;AAAA,IACJ;AAAA,EACF,CAAC;AAIL,QAAM,gBAAgB,eAAeA,QAAO,MAAM,IAAIA,QAAO,SAAS;AACtE,QAAM,sBAAsB,MAAM;AAAA,IAChC;AAAA,IACA;AAAA,EACF;AAIA,QAAM,gBAAgB;AAAA,IACpB,gBAAgBA,QAAO;AAAA,IACvB,cAAc,eAAe;AAAA,IAC7B,WAAW;AAAA;AAAA,IACX,gCAAgC;AAAA;AAAA,IAChC,uBAAuB,CAAC,yBAAyB;AAAA;AAAA,EACnD;AAEA,QAAM,qBAAqB,sBACvB,IAAQ,YAAO;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,MACE,QAAQ;AAAA;AAAA,IACV;AAAA,EACF,IACA,IAAQ,YAAO;AAAA,IACb;AAAA,IACA;AAAA,EACF;AAEJ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;;;ACvUA;AAAA,YAAYC,UAAS;AA0BrB,eAAe,uBACb,eACA,QACkB;AAClB,MAAI;AACF,UAAM,EAAE,aAAAC,cAAa,4BAAAC,4BAA2B,IAAI,MAAM,OACxD,uBACF;AACA,UAAM,MAAM,IAAID,aAAY,EAAE,OAAO,CAAC;AAEtC,UAAM,IAAI;AAAA,MACR,IAAIC,4BAA2B,EAAE,sBAAsB,cAAc,CAAC;AAAA,IACxE;AACA,WAAO;AAAA,EACT,SAAS,OAAY;AACnB,QAAI,MAAM,SAAS,qBAAqB;AACtC,aAAO;AAAA,IACT;AACA,YAAQ,MAAM,kDAAkD,KAAK;AACrE,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,uBACpB,eACA,eACA,QACkB;AAClB,MAAI;AACF,UAAM,EAAE,aAAAD,cAAa,4CAA4C,IAC/D,MAAM,OAAO,uBAAuB;AACtC,UAAM,MAAM,IAAIA,aAAY,EAAE,OAAO,CAAC;AAEtC,UAAM,WAAW,MAAM,IAAI;AAAA,MACzB,IAAI,4CAA4C;AAAA,QAC9C,sBAAsB;AAAA,MACxB,CAAC;AAAA,IACH;AAEA,WACE,SAAS,mBAAmB,KAAK,CAAC,SAAS,KAAK,SAAS,aAAa,KACtE;AAAA,EAEJ,SAAS,OAAY;AACnB,QAAI,MAAM,SAAS,qBAAqB;AACtC,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AACF;AAKA,eAAe,oBACb,eACA,QACkB;AAClB,MAAI;AACF,UAAM,EAAE,aAAAA,cAAa,yBAAAE,yBAAwB,IAAI,MAAM,OACrD,uBACF;AACA,UAAM,MAAM,IAAIF,aAAY,EAAE,OAAO,CAAC;AAEtC,UAAM,IAAI;AAAA,MACR,IAAIE,yBAAwB,EAAE,eAAe,cAAc,CAAC;AAAA,IAC9D;AACA,WAAO;AAAA,EACT,SAAS,OAAY;AACnB,QAAI,MAAM,SAAS,qBAAqB;AACtC,aAAO;AAAA,IACT;AACA,YAAQ,MAAM,+CAA+C,KAAK;AAClE,WAAO;AAAA,EACT;AACF;AAkBA,eAAsB,mBACpBC,SACuB;AAEvB,QAAM,mBAAmD;AAAA,IACvD,sBAAsB;AAAA,IACtB,iBAAiBA,QAAO,cACpB;AAAA,MACE,WAAW;AAAA;AAAA,IACb,IACA;AAAA,IACJ,oBAAoB;AAAA;AAAA;AAAA,MAGlB,mBAAmB,CAAC,UAAU,WAAW;AAAA,IAC3C;AAAA,IACA,MAAM;AAAA,MACJ,WAAW;AAAA,MACX,aAAa;AAAA,IACf;AAAA,EACF;AAMA,MAAIA,QAAO,gBAAgB,sBAAsB;AAC/C,qBAAiB,kBAAkB;AAAA,MACjC,sBAAsBA,QAAO,eAAe;AAAA;AAAA;AAAA;AAAA,MAI5C,aAAaA,QAAO,eAAe,eAAe,YAAY;AAAA,IAChE;AAAA,EACF;AAGA,QAAM,gBAAgB;AACtB,QAAM,SAAS,MAAM,uBAAuB,eAAeA,QAAO,MAAM;AAExE,QAAM,YAAY,SACd,IAAQ,WAAM,iBAAiB,eAAe,kBAAkB;AAAA,IAC9D,QAAQ;AAAA;AAAA,EACV,CAAC,IACD,IAAQ,WAAM,iBAAiB,eAAe,gBAAgB;AAKlE,QAAM,kBAAsB,gBAAW,kBAAkB;AAAA,IACvD,MAAM;AAAA,EACR,CAAC;AAID,MAAIA,QAAO,sBAAsB;AAC/B,UAAM,gBAAgB;AAEtB,QAAQ,WAAM;AAAA,MACZ;AAAA,MACA;AAAA,QACE,sBAAsB,UAAU;AAAA,QAChC,sBAAsB;AAAA,QACtB,kBAAkB;AAAA,UAChB,SAAS;AAAA,UACT,oBAAoB;AAAA,YAClB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UACA,wBAAwB;AAAA;AAAA,YAEtB,aAAa,gBAAgB;AAAA,UAC/B;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA;AAAA;AAAA,QAGE,QAAQA,QAAO,iCACX,wBAAwB,aAAa,KACrC;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAGA,MAAI;AACJ,MAAI;AACJ,MAAI;AAEJ,MAAIA,QAAO,QAAQ;AAEjB,UAAM,iBAAiB,MAAM;AAAA,MAC3BA,QAAO;AAAA,MACPA,QAAO;AAAA,IACT;AAGA,qBAAiB,iBACb,IAAQ,WAAM;AAAA,MACZ;AAAA,MACA;AAAA,QACE,eAAeA,QAAO;AAAA,QACtB,sBAAsB,UAAU;AAAA;AAAA,QAChC,uBAAuB;AAAA,UACrB,sBAAsB;AAAA,QACxB;AAAA,QACA,MAAM;AAAA,UACJ,WAAW;AAAA,QACb;AAAA,MACF;AAAA,MACA;AAAA,QACE,QAAQA,QAAO;AAAA;AAAA,MACjB;AAAA,IACF,IACA,IAAQ,WAAM,cAAc,sBAAsB;AAAA,MAChD,eAAeA,QAAO;AAAA,MACtB,sBAAsB,UAAU;AAAA;AAAA,MAChC,uBAAuB;AAAA,QACrB,sBAAsB;AAAA,MACxB;AAAA,MACA,MAAM;AAAA,QACJ,WAAW;AAAA,MACb;AAAA,IACF,CAAC;AAGL,iBAAa,eAAe,sBAAsB;AAAA,MAChD,CAAC,UAAU,OAAO,UAAU,CAAC;AAAA,IAC/B;AAGA,QAAIA,QAAO,gBAAgB;AACzB,uBAAiBA,QAAO;AAIxB,UAAQ,WAAM;AAAA,QACZ;AAAA,QACA;AAAA,UACE,eAAeA,QAAO;AAAA,UACtB;AAAA,UACA,qBAAqB;AAAA;AAAA,QACvB;AAAA,QACA;AAAA,UACE,WAAW,CAAC,cAAc;AAAA;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA;AAAA,IACV;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA;AAAA,IAChB,sBAAsBA,QAAO,gBAAgB;AAAA,IAC7C;AAAA,EACF;AACF;;;ACnSA;AAAA,YAAYC,UAAS;AAkBrB,eAAsB,qBAA4C;AAEhE,QAAM,MAAM,IAAQ,SAAI,MAAM,0BAA0B;AAAA,IACtD,MAAM;AAAA,IACN,yBAAyB;AAAA;AAAA,IACzB,MAAM;AAAA,MACJ,WAAW;AAAA,MACX,aAAa;AAAA,IACf;AAAA,EACF,CAAC;AAGD,QAAM,QAAQ,IAAQ,SAAI,MAAM,sBAAsB;AAAA,IACpD,MAAM;AAAA,IACN,0BAA0B;AAAA;AAAA,IAC1B,yBAAyB;AAAA;AAAA,IACzB,wBAAwB;AAAA;AAAA,IACxB,eAAe,IAAI,IAAI;AAAA,MAAM,CAAC,QAC5B,KAAK,UAAU;AAAA,QACb,qBAAqB;AAAA,QACrB,iBAAiB;AAAA;AAAA,MACnB,CAAC;AAAA,IACH;AAAA,IACA,MAAM;AAAA,MACJ,WAAW;AAAA,MACX,aAAa;AAAA,IACf;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;;;ACnDA;AAAA,YAAYC,UAAS;AAarB,eAAe,2BAA2B,KAAqC;AAC7E,MAAI;AACF,UAAM,EAAE,WAAAC,YAAW,kCAAkC,IAAI,MAAM,OAC7D,qBACF;AAEA,UAAMC,OAAM,IAAID,WAAU;AAAA,MACxB,QAAQ,QAAQ,IAAI,cAAc;AAAA,IACpC,CAAC;AAED,UAAM,WAAW,MAAMC,KAAI,KAAK,IAAI,kCAAkC,CAAC,CAAC,CAAC;AAIzE,UAAM,oBAAoB,IAAI,QAAQ,YAAY,EAAE;AACpD,UAAM,WAAW,SAAS,2BAA2B;AAAA,MAAK,CAAC,MACzD,EAAE,KAAK,SAAS,iBAAiB;AAAA,IACnC;AAEA,WAAO,UAAU,OAAO;AAAA,EAC1B,SAAS,OAAO;AACd,YAAQ,MAAM,8CAA8C,KAAK;AACjE,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,iBACpBC,SACwC;AACxC,QAAM,MAAM,2BAA2BA,QAAO,QAAQ;AAGtD,QAAM,cAAc,MAAM,2BAA2B,GAAG;AAExD,MAAI,aAAa;AAEf,WAAO,IAAQ,SAAI;AAAA,MACjB;AAAA,MACA;AAAA,QACE;AAAA,QACA,eAAe,CAAC,sBAAsBA,QAAO,QAAQ,EAAE;AAAA,QACvD,iBAAiB;AAAA;AAAA,UAEf;AAAA,UACA;AAAA,QACF;AAAA,QACA,MAAM;AAAA,UACJ,WAAW;AAAA,UACX,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,MACA;AAAA,QACE,QAAQ;AAAA;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAGA,SAAO,IAAQ,SAAI,sBAAsB,qBAAqB;AAAA,IAC5D;AAAA,IACA,eAAe,CAAC,sBAAsBA,QAAO,QAAQ,EAAE;AAAA,IACvD,iBAAiB;AAAA;AAAA,MAEf;AAAA,MACA;AAAA,IACF;AAAA,IACA,MAAM;AAAA,MACJ,WAAW;AAAA,MACX,UAAU;AAAA,IACZ;AAAA,EACF,CAAC;AACH;;;APzEA,eAAsB,iBACpBC,SACuB;AAEvB,QAAM,WAAW,MAAU,wBAAkB;AAC7C,QAAM,YAAY,SAAS;AAE3B,MAAI;AAGJ,MAAIA,QAAO,aAAa,YAAYA,QAAO,QAAQ;AACjD,mBAAe,MAAM,iBAAiB;AAAA,MACpC,UAAUA,QAAO,OAAO;AAAA,MACxB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,cAAcA,QAAO;AAG3B,QAAM,OAAO,MAAM,cAAc;AAAA,IAC/B,UAAUA,QAAO;AAAA,IACjB;AAAA,IACA,gBAAgBA,QAAO,QAAQ;AAAA,IAC/B,mBAAmBA,QAAO,QAAQ;AAAA,IAClC;AAAA,EACF,CAAC;AAGD,MAAI;AACJ,MAAI;AAEJ,MACE,YAAY,UAAU,WACtB,YAAY,SAAS,wBACrB,YAAY,SAAS,cACrB;AAEA,UAAM,EAAE,gBAAAC,gBAAe,IAAI,MAAM;AACjC,UAAM,aAAa,MAAMA;AAAA,MACvB,YAAY,SAAS;AAAA,MACrBD,QAAO;AAAA,IACT;AAGA,UAAM,EAAE,sBAAAE,sBAAqB,IAAI,MAAM;AACvC,mBAAe,MAAMA,sBAAqB;AAAA,MACxC,QAAQ,YAAY,SAAS;AAAA,MAC7B,cAAc,YAAY;AAAA,IAC5B,CAAC;AAID,UAAM,EAAE,0BAAAC,0BAAyB,IAAI,MAAM;AAO3C,UAAM,iBAAiB,aAAa,wBAChC,aAAa,sBAAsB,iBACnC,aAAa,YAAY;AAE7B,0BAAsB,MAAMA,0BAAyB;AAAA,MACnD,sBAAsB,YAAY,SAAS;AAAA,MAC3C,QAAQH,QAAO;AAAA,MACf;AAAA,MACA,cAAc,YAAY;AAAA;AAAA,IAC5B,CAAC;AAAA,EACH;AAGA,MAAI;AACJ,MAAI,YAAY,UAAU,WAAW,YAAY,eAAe,SAAS;AAGvE,UAAM,wBACJ,YAAY,eAAe,WAC1B,MAAM;AAAA,MACL;AAAA,MACA;AAAA,MACAA,QAAO;AAAA,IACT;AAGF,QAAI,iBAAiB,YAAY;AACjC,QAAI,CAAC,kBAAkB,YAAY,qBAAqB,YAAY,QAAQ;AAC1E,uBAAiB,GAAG,YAAY,iBAAiB,IAAI,YAAY,MAAM;AAAA,IACzE;AAEA,mBAAe,MAAM,mBAAmB;AAAA,MACtC,QAAQ,YAAY;AAAA,MACpB;AAAA,MACA,QAAQA,QAAO;AAAA,MACf,gBAAgB,YAAY;AAAA,MAC5B,YAAY,YAAY,eAAe;AAAA,MACvC,sBAAsB,YAAY,eAAe;AAAA;AAAA,MACjD,aAAa,YAAY;AAAA;AAAA,MACzB,gCAAgC;AAAA;AAAA,IAClC,CAAC;AAAA,EACH;AAGA,MAAI;AACJ,MAAI,YAAY,eAAe,iBAAiB;AAC9C,mBAAe,MAAM,qBAAqB;AAAA,MACxC,WAAW,YAAY,cAAc;AAAA,IACvC,CAAC;AAAA,EACH;AAGA,MAAI;AACJ,MAAI,YAAY,eAAe,SAAS;AACtC,mBAAe,MAAM,mBAAmB;AAAA,EAC1C;AAGA,MAAI,YAAY,eAAe,WAAW,gBAAgB,cAAc;AACtE,UAAM,2BAA2B;AAAA,MAC/B,aAAa,aAAa,SAAS;AAAA,MACnC,UAAU,aAAa,MAAM;AAAA,MAC7B,UAAU,aAAa,MAAM;AAAA,IAC/B,CAAC;AAAA,EACH;AAGA,MAAI;AACJ,MACE,YAAY,eAAe,mBAC3B,gBACA,cACA;AACA,sBAAkB,MAAM,sBAAsB;AAAA,MAC5C,SAAS,KAAK;AAAA,MACd,WAAW,aAAa,aAAa;AAAA,MACrC,UAAU,aAAa,MAAM;AAAA,MAC7B;AAAA,MACA,QAAQA,QAAO;AAAA,IACjB,CAAC;AAAA,EACH;AAGA,MAAI;AACJ,MAAI,YAAY,gBAAgB,WAAW,cAAc;AACvD,UAAM,EAAE,0BAAAI,0BAAyB,IAAI,MAAM;AAG3C,uBAAmB,MAAMA,0BAAyB;AAAA,MAChD,MAAM;AAAA,MACN,WAAW,YAAY,eAAe;AAAA,MACtC,eAAe,aAAa,UAAU;AAAA,MACtC,QAAQJ,QAAO;AAAA,IACjB,CAAC;AAAA,EACH;AAGA,SAAO;AAAA,IACL,SAAS,KAAK;AAAA,IACd,eAAe,cAAc,UAAU;AAAA,IAGvC,WAAW,cAAc,aAAa;AAAA,IACtC,QAAQA,QAAO;AAAA,IACf,iBAAiB,kBACb,CAAC,gBAAgB,eAAe,GAAoB,IACpD;AAAA,IACJ,QAAQ,YAAY;AAAA,IACpB,YAAY,cAAc;AAAA,IAC1B,gBAAgB,cAAc;AAAA,IAC9B,cAAc,cAAc,SAAS;AAAA,IACrC,UAAU,cAAc,MAAM;AAAA,IAC9B,QAAQ,cAAc,IAAI;AAAA,IAC1B,sBAAsB,cAAc;AAAA,IACpC,sBAAsB,YAAY,UAAU;AAAA,IAC5C,kBAAkB,qBAAqB;AAAA,IAGvC,iCAAiC,cAAc;AAAA,IAG/C,gBAAgB,cAAc;AAAA,IAC9B,YAAY,kBAAkB;AAAA,IAC9B,kBAAkB,YAAY,gBAAgB;AAAA,IAC9C,kBAAkB,YAAY,gBAAgB,UAC1C,YAAY,eAAe,YAC3B;AAAA,EACN;AACF;;;ADtMA;AAKA;AAIA;;;ASbA;AAGA;AAHA,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAC1B,YAAYK,iBAAgB;AAG5B,IAAM,YAAY,UAAU,IAAI;AAGhC,IAAMC,oBAAuC;AAK7C,eAAsB,uBAAyC;AAC7D,MAAI;AACF,UAAM,UAAU,gBAAgB;AAChC,WAAO;AAAA,EACT,SAAS,QAAQ;AACf,WAAO;AAAA,EACT;AACF;AAMA,eAAsB,wBAA0C;AAC9D,QAAM,cAAc,MAAM,qBAAqB;AAE/C,MAAI,CAAC,aAAa;AAChB,QAAI;AAEF,YAAMA,kBAAiB;AACvB,aAAO;AAAA,IACT,SAAS,QAAQ;AAEf,YAAM,OAAO,mBAAmB;AAAA,IAClC;AAAA,EACF;AAEA,SAAO;AACT;;;ATPA,eAAsB,OAAO,SAA4C;AACvE,QAAM,YAAY,KAAK,IAAI;AAE3B,EAAM;AAAA,IACJC,IAAG;AAAA,MACD,QAAQ,UACJ,yBACA;AAAA,IACN;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,mBAAmB;AAGxC,QAAM,mBAAmB,MAAM,SAAS;AAAA,IACtC;AAAA,IACA,YAAY,MAAM,sBAAsB;AAAA,EAC1C;AAEA,MAAI,kBAAkB;AACpB,aAAS,KAAK,wCAAwC;AAAA,EACxD;AAGA,QAAM,WAAW,MAAM,SAAS;AAAA,IAC9B;AAAA,IACA,YAAY,uBAAuB;AAAA,EACrC;AAEA,WAAS,KAAK,6BAA6BA,IAAG,KAAK,SAAS,SAAS,CAAC,EAAE;AAGxE,MAAI,SAAS,QAAQ;AACrB,MAAI,CAAC,QAAQ;AACX,UAAM,gBAAgB,MAAM,aAAa;AACzC,aAAS;AAAA,EACX;AAGA,QAAM,WAAW,MAAM,uBAAuB,SAAS,WAAW,MAAM;AAExE,MAAI,CAAC,UAAU;AACb,IAAM,WAAI;AAAA,MACR,yCAAyCA,IAAG,KAAK,SAAS,SAAS,CAAC,cAAcA,IAAG,KAAK,MAAM,CAAC;AAAA,IACnG;AACA,IAAM,WAAI;AAAA,MACR,OAAOA,IAAG,KAAK,kBAAkB,CAAC,oCAAoCA,IAAG,KAAK,qBAAqB,CAAC;AAAA,IACtG;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,WAAS,KAAK,sCAAsC,SAAS,SAAS,EAAE;AAGxE,UAAQ,IAAI;AAAA,EAAKA,IAAG,KAAK,wBAAwB,CAAC;AAAA,CAAI;AAEtD,MAAI,SAAS,SAAS,OAAO,QAAQ;AACnC,YAAQ,IAAI,aAAaA,IAAG,KAAK,SAAS,SAAS,OAAO,MAAM,CAAC,EAAE;AAAA,EACrE,OAAO;AACL,YAAQ,IAAI,aAAaA,IAAG,KAAK,QAAQ,CAAC,EAAE;AAAA,EAC9C;AAEA,QAAMC,UAAS,SAAS,SAAS,OAAO;AAExC,MAAI,CAACA,SAAQ;AACX,IAAM,WAAI,MAAM,0CAA0C;AAC1D,IAAM,WAAI;AAAA,MACR,OAAOD,IAAG,KAAK,kBAAkB,CAAC;AAAA,IACpC;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,MAAIC,QAAO,QAAQ;AACjB,YAAQ,IAAI,qBAAqBD,IAAG,KAAKC,QAAO,MAAM,CAAC,EAAE;AAAA,EAC3D;AAEA,MAAIA,QAAO,UAAU,SAAS;AAC5B,YAAQ,IAAI,KAAKD,IAAG,MAAM,QAAG,CAAC,wBAAwB;AAAA,EACxD;AAEA,MAAIC,QAAO,iBAAiB,SAAS;AACnC,YAAQ,IAAI,KAAKD,IAAG,MAAM,QAAG,CAAC,+BAA+B;AAAA,EAC/D;AAEA,MAAIC,QAAO,eAAe,SAAS;AACjC,YAAQ,IAAI,KAAKD,IAAG,MAAM,QAAG,CAAC,+BAA+B;AAAA,EAC/D;AAEA,MAAIC,QAAO,aAAa;AACtB,YAAQ,IAAI,KAAKD,IAAG,MAAM,QAAG,CAAC,uBAAuB;AAAA,EACvD;AAEA,UAAQ,IAAI,EAAE;AAGd,UAAQ,IAAI,GAAGA,IAAG,KAAK,uBAAuB,CAAC;AAAA,CAAI;AACnD,UAAQ;AAAA,IACN,KAAKA,IAAG,KAAK,QAAG,CAAC;AAAA,EACnB;AACA,UAAQ;AAAA,IACN,KAAKA,IAAG,KAAK,QAAG,CAAC;AAAA,EACnB;AACA,UAAQ,IAAI,KAAKA,IAAG,KAAK,QAAG,CAAC,uCAAuC;AACpE,UAAQ,IAAI,KAAKA,IAAG,KAAK,QAAG,CAAC,0CAA0C;AACvE,UAAQ,IAAI,EAAE;AAEd,WAAS;AAAA,IACP;AAAA,EACF;AACA,UAAQ,IAAI,EAAE;AAGd,MAAI,EAAE,QAAQ,OAAO,QAAQ,UAAU;AACrC,UAAM,YAAY,MAAY,eAAQ;AAAA,MACpC,SAAS;AAAA,MACT,cAAc;AAAA,IAChB,CAAC;AAED,QAAU,gBAAS,SAAS,KAAK,CAAC,WAAW;AAC3C,MAAM,cAAO,mBAAmB;AAChC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAGA,MAAI;AACJ,MAAI,SAAS,aAAa,YAAY,SAAS,QAAQ;AACrD,mBAAe,SAAS;AAAA,EAC1B;AAGA,QAAM,cAAgC;AAAA,IACpC,UAAU,SAAS;AAAA,IACnB;AAAA,IACA,QAAQ;AAAA,IACR,aAAaC;AAAA,EACf;AAGA,MAAI,QAAQ,SAAS;AAEnB,QAAI;AACF,YAAM,gBAAgB,MAAM,SAAS;AAAA,QACnC;AAAA,QACA,YAAY;AACV,gBAAM,oBAAoB;AAE1B,gBAAM,QACJ,MAAa,mBAAW,eAAe;AAAA,YACrC;AAAA,cACE,WACE,SAAS,SAAS,OAAO,mBACzB,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,cACvC,aAAa;AAAA,cACb,SAAS,YAAY;AACnB,sBAAMC,UAAS,MAAM,iBAAiB,WAAW;AACjD,uBAAO;AAAA,kBACL,SAASA,QAAO;AAAA,kBAChB,eAAeA,QAAO;AAAA,kBACtB,WAAWA,QAAO;AAAA,kBAClB,QAAQA,QAAO;AAAA,kBACf,iBAAiBA,QAAO;AAAA,kBACxB,QAAQA,QAAO;AAAA,kBACf,YAAYA,QAAO;AAAA,kBACnB,sBAAsBA,QAAO;AAAA,gBAC/B;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,SAAS,iBAAiB;AAAA,cAC1B,SAAS;AAAA,gBACP,0BAA0B;AAAA,gBAC1B,YAAY;AAAA,cACd;AAAA,cACA,iBAAiB;AAAA,YACnB;AAAA,UACF;AAEF,gBAAM,MAAM,UAAU,cAAc,EAAE,OAAO,OAAO,CAAC;AAGrD,gBAAM,MAAM,QAAQ,EAAE,UAAU,MAAM;AAAA,UAAC,EAAE,CAAC;AAG1C,gBAAM,SAAS,MAAM,MAAM,QAAQ,EAAE,MAAM,KAAK,CAAC;AACjD,iBAAO;AAAA,QACT;AAAA,MACF;AAGA,qBAAe;AAAA,QACb,eAAe,cAAc;AAAA,QAC7B,aAAa;AAAA,MACf,CAAC;AAED,MAAM;AAAA,QACJF,IAAG,MAAM,oDAAoD;AAAA,MAC/D;AAGA,mBAAa,gBAAgB;AAAA,QAC3B,SAAS;AAAA,QACT,SAAS;AAAA,QACT,aAAa,KAAK,IAAI,IAAI;AAAA,MAC5B,CAAC;AACD;AAAA,IACF,SAAS,OAAY;AACnB,iBAAW,kBAAkB,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAChE,UAAI,MAAM,SAAS,SAAS,2BAA2B,GAAG;AACxD,cAAM,OAAO,YAAY;AAAA,MAC3B;AACA,YAAM,IAAI,MAAM,mBAAmB,MAAM,OAAO,EAAE;AAAA,IACpD;AAAA,EACF;AAGA,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,SAAS;AAAA,MACvB;AAAA,MACA,YAAY;AACV,cAAM,oBAAoB;AAE1B,cAAM,QACJ,MAAa,mBAAW,eAAe;AAAA,UACrC;AAAA,YACE,WACE,SAAS,SAAS,OAAO,mBACzB,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,YACvC,aAAa;AAAA,YACb,SAAS,YAAY;AACnB,oBAAM,SAAS,MAAM,iBAAiB,WAAW;AAEjD,qBAAO;AAAA,gBACL,SAAS,OAAO;AAAA,gBAChB,eAAe,OAAO;AAAA,gBACtB,WAAW,OAAO;AAAA,gBAClB,QAAQ,OAAO;AAAA,gBACf,iBAAiB,OAAO;AAAA,gBACxB,QAAQ,OAAO;AAAA,gBACf,YAAY,OAAO;AAAA,gBACnB,sBAAsB,OAAO;AAAA,cAC/B;AAAA,YACF;AAAA,UACF;AAAA,UACA;AAAA,YACE,SAAS,iBAAiB;AAAA,YAC1B,SAAS;AAAA,cACP,0BAA0B;AAAA,cAC1B,YAAY;AAAA,YACd;AAAA,YACA,iBAAiB;AAAA,UACnB;AAAA,QACF;AAEF,cAAM,MAAM,UAAU;AAAA,UACpB,SAAS,SAAS,OAAO,mBACvB,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,QACzC;AACA,cAAM,MAAM,UAAU,cAAc,EAAE,OAAO,OAAO,CAAC;AAGrD,cAAM,MAAM,QAAQ,EAAE,UAAU,MAAM;AAAA,QAAC,EAAE,CAAC;AAG1C,cAAM,WAAW,MAAM,MAAM,GAAG,EAAE,UAAU,MAAM;AAAA,QAAC,EAAE,CAAC;AACtD,cAAM,gBAAgB,SAAS;AAE/B,eAAO;AAAA,UACL,SAAS,cAAc,SAAS;AAAA,UAChC,eAAe,cAAc,eAAe;AAAA,UAG5C,WAAW,cAAc,WAAW;AAAA,UACpC,QAAQ,cAAc,QAAQ;AAAA,UAC9B,iBAAiB,cAAc,iBAAiB;AAAA,UAGhD,QAAQ,cAAc,QAAQ;AAAA,UAC9B,YAAY,cAAc,YAAY;AAAA,UACtC,sBAAsB,cAAc,sBAAsB;AAAA,QAG5D;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAY;AAEnB,iBAAa,gBAAgB;AAAA,MAC3B,SAAS;AAAA,MACT,aAAa,KAAK,IAAI,IAAI;AAAA,IAC5B,CAAC;AAGD,QAAI,MAAM,SAAS,SAAS,2BAA2B,GAAG;AACxD,iBAAW,gBAAgB,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC7D,YAAM,OAAO,YAAY;AAAA,IAC3B;AAEA,eAAW,iBAAiB,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC9D,UAAM,IAAI,MAAM,yBAAyB,MAAM,OAAO,EAAE;AAAA,EAC1D;AAGA,WAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC5C,QAAM,uBAAuB,QAAQ;AAErC,WAAS,KAAK,6BAA6B;AAG3C,iBAAe;AAAA,IACb,SAAS,QAAQ;AAAA,IACjB,eAAe,QAAQ;AAAA,IACvB,QAAQ,QAAQ;AAAA,IAChB,WAAW,QAAQ;AAAA,IACnB,sBAAsB,QAAQ;AAAA,EAChC,CAAC;AAGD,UAAQ,IAAI;AAAA,EAAKA,IAAG,MAAM,QAAG,CAAC,IAAIA,IAAG,KAAK,kBAAkB,CAAC;AAAA,CAAI;AACjE,UAAQ;AAAA,IACN;AAAA,EACF;AACA,UAAQ,IAAI,GAAGA,IAAG,KAAK,aAAa,CAAC;AAAA,CAAI;AACzC,UAAQ;AAAA,IACN,KAAKA,IAAG,KAAK,IAAI,CAAC;AAAA,EACpB;AACA,UAAQ;AAAA,IACN,KAAKA,IAAG,KAAK,IAAI,CAAC,UAAUA,IAAG,KAAK,cAAc,CAAC;AAAA,EACrD;AACA,UAAQ;AAAA,IACN,KAAKA,IAAG,KAAK,IAAI,CAAC,sBAAsBA,IAAG,KAAK,eAAe,CAAC;AAAA;AAAA,EAClE;AAGA,eAAa,gBAAgB;AAAA,IAC3B,SAAS;AAAA,IACT,aAAa,KAAK,IAAI,IAAI;AAAA,EAC5B,CAAC;AACH;;;AUtXA;AAAA,YAAYG,YAAW;AACvB,YAAYC,aAAY;AACxB,OAAOC,SAAQ;AAEf;AAMA;AACA;AAIA;AAeA;;;AC9BA;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAAC,YAAW,wBAAwB;AAC5C,SAAS,cAAc,4BAA4B;AACnD;AAAA,EACE;AAAA,EACA,4CAAAC;AAAA,EACA;AAAA,EACA,yBAAAC;AAAA,EACA,aAAAC;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAgFP,eAAsB,kBACpB,QACwB;AACxB,QAAM,MAAM,IAAIA,WAAU,EAAE,OAAO,CAAC;AACpC,QAAM,aAA4B,CAAC;AAEnC,MAAI;AAEF,UAAM,eAAe,MAAM,IAAI,KAAK,IAAID,uBAAsB,CAAC,CAAC,CAAC;AACjE,UAAM,gBAAgB,aAAa,cAAc,CAAC;AAElD,QAAI,cAAc,WAAW,GAAG;AAC9B,aAAO,CAAC;AAAA,IACV;AAGA,UAAM,gBAAgB,MAAM,IAAI;AAAA,MAC9B,IAAID,0CAAyC;AAAA,QAC3C,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AAEA,UAAM,QAAQ,cAAc,0BAA0B,CAAC;AAGvD,eAAW,QAAQ,eAAe;AAChC,YAAM,OAAO,MAAM,IAAI;AACvB,iBAAW,KAAK;AAAA,QACd;AAAA,QACA,MAAM,KAAK,SAAS,GAAG,IAAI,iBAAiB;AAAA,QAC5C,UAAU,MAAM,uBAAuB;AAAA,MACzC,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT,SAAS,OAAY;AACnB,YAAQ,MAAM,kCAAkC,MAAM,OAAO;AAC7D,WAAO,CAAC;AAAA,EACV;AACF;AAKA,eAAsB,yBACpB,QACgC;AAChC,QAAM,MAAM,IAAIE,WAAU,EAAE,OAAO,CAAC;AACpC,QAAM,aAAoC,CAAC;AAE3C,MAAI;AAEF,UAAM,eAAe,MAAM,IAAI,KAAK,IAAI,6BAA6B,CAAC,CAAC,CAAC;AACxE,UAAM,iBACJ,aAAa,mBAAmB,IAAI,CAAC,OAAO,GAAG,IAAK,EAAE,OAAO,OAAO,KACpE,CAAC;AAGH,eAAW,QAAQ,gBAAgB;AACjC,UAAI;AACF,cAAM,mBAAmB,MAAM,IAAI;AAAA,UACjC,IAAI,gCAAgC,EAAE,sBAAsB,KAAK,CAAC;AAAA,QACpE;AAEA,cAAM,oBACJ,iBAAiB,mBAAmB,IAAI,CAAC,QAAQ;AAAA,UAC/C,MAAM,GAAG;AAAA,UACT,SAAS,GAAG,WAAW;AAAA,UACvB,oBAAoB,GAAG,sBAAsB,CAAC;AAAA,UAC9C,gBAAgB,GAAG,gBAAgB;AAAA,UACnC,uBAAuB,GAAG;AAAA,QAC5B,EAAE,KAAK,CAAC;AAEV,mBAAW,KAAK;AAAA,UACd;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH,SAAS,OAAY;AACnB,gBAAQ,MAAM,+BAA+B,IAAI,KAAK,MAAM,OAAO;AAAA,MACrE;AAAA,IACF;AAEA,WAAO;AAAA,EACT,SAAS,OAAY;AACnB,YAAQ,MAAM,0CAA0C,MAAM,OAAO;AACrE,WAAO,CAAC;AAAA,EACV;AACF;AAKA,eAAsB,cAAc,QAAqC;AACvE,QAAM,MAAM,IAAI,UAAU,EAAE,OAAO,CAAC;AACpC,QAAM,SAAqB,CAAC;AAE5B,MAAI;AAEF,UAAM,eAAe,MAAM,IAAI,KAAK,IAAI,kBAAkB,CAAC,CAAC,CAAC;AAC7D,UAAM,YACJ,aAAa,QAAQ,IAAI,CAAC,MAAM,EAAE,QAAS,EAAE,OAAO,OAAO,KAAK,CAAC;AAGnE,eAAW,OAAO,WAAW;AAC3B,UAAI;AACF,cAAM,gBAAgB,MAAM,IAAI;AAAA,UAC9B,IAAI,0BAA0B,EAAE,UAAU,IAAI,CAAC;AAAA,QACjD;AAEA,cAAM,OAAO,IAAI,MAAM,GAAG,EAAE,IAAI,KAAK;AACrC,cAAM,gBAAgB,OAAO;AAAA,UAC3B,cAAc,YAAY,0BAA0B;AAAA,UACpD;AAAA,QACF;AAEA,eAAO,KAAK;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH,SAAS,OAAY;AACnB,gBAAQ;AAAA,UACN,sCAAsC,GAAG;AAAA,UACzC,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT,SAAS,OAAY;AACnB,YAAQ,MAAM,8BAA8B,MAAM,OAAO;AACzD,WAAO,CAAC;AAAA,EACV;AACF;AAKA,eAAsB,iBAAiB,QAAwC;AAC7E,QAAM,SAAS,IAAI,eAAe,EAAE,OAAO,CAAC;AAC5C,QAAM,SAAwB,CAAC;AAE/B,MAAI;AAEF,UAAM,eAAe,MAAM,OAAO,KAAK,IAAI,kBAAkB,CAAC,CAAC,CAAC;AAChE,UAAM,aAAa,aAAa,cAAc,CAAC;AAG/C,eAAW,QAAQ,YAAY;AAC7B,UAAI;AACF,cAAM,mBAAmB,MAAM,OAAO;AAAA,UACpC,IAAI,qBAAqB,EAAE,WAAW,KAAK,CAAC;AAAA,QAC9C;AAEA,cAAM,QAAQ,iBAAiB;AAC/B,YAAI,OAAO;AACT,iBAAO,KAAK;AAAA,YACV;AAAA,YACA,QAAQ,MAAM,eAAe;AAAA,YAC7B,WAAW,MAAM;AAAA,YACjB,WAAW,MAAM;AAAA,UACnB,CAAC;AAAA,QACH;AAAA,MACF,SAAS,OAAY;AACnB,gBAAQ,MAAM,0BAA0B,IAAI,KAAK,MAAM,OAAO;AAAA,MAChE;AAAA,IACF;AAEA,WAAO;AAAA,EACT,SAAS,OAAY;AACnB,YAAQ,MAAM,mCAAmC,MAAM,OAAO;AAC9D,WAAO,CAAC;AAAA,EACV;AACF;AAKA,eAAsB,oBACpB,QAC2B;AAC3B,QAAMC,UAAS,IAAI,aAAa,EAAE,OAAO,CAAC;AAC1C,QAAM,YAA8B,CAAC;AAErC,MAAI;AAEF,UAAM,eAAe,MAAMA,QAAO,KAAK,IAAI,qBAAqB,CAAC,CAAC,CAAC;AACnE,UAAM,kBAAkB,aAAa,aAAa,CAAC;AAEnD,eAAW,QAAQ,iBAAiB;AAClC,UAAI,KAAK,gBAAgB,KAAK,aAAa;AACzC,kBAAU,KAAK;AAAA,UACb,MAAM,KAAK;AAAA,UACX,KAAK,KAAK;AAAA,UACV,SAAS,KAAK;AAAA,UACd,SAAS,KAAK;AAAA,QAChB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,EACT,SAAS,OAAY;AACnB,YAAQ,MAAM,oCAAoC,MAAM,OAAO;AAC/D,WAAO,CAAC;AAAA,EACV;AACF;AAKA,eAAsB,aAAa,QAAoC;AACrE,QAAMC,OAAM,IAAIL,WAAU,EAAE,OAAO,CAAC;AACpC,QAAM,QAAmB,CAAC;AAE1B,MAAI;AAEF,QAAI;AACJ,QAAI,UAAU;AAEd,WAAO,SAAS;AACd,YAAM,eAAe,MAAMK,KAAI;AAAA,QAC7B,IAAI,iBAAiB;AAAA,UACnB,QAAQ;AAAA,UACR,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAEA,YAAM,WAAW,aAAa,SAAS,CAAC;AAExC,iBAAW,QAAQ,UAAU;AAC3B,YAAI,KAAK,YAAY,KAAK,KAAK;AAC7B,gBAAM,KAAK;AAAA,YACT,MAAM,KAAK;AAAA,YACX,KAAK,KAAK;AAAA,YACV,0BAA0B,KAAK,4BAA4B;AAAA,UAC7D,CAAC;AAAA,QACH;AAAA,MACF;AAEA,eAAS,aAAa;AACtB,gBAAU,aAAa,eAAe;AAAA,IACxC;AAEA,WAAO;AAAA,EACT,SAAS,OAAY;AACnB,YAAQ,MAAM,6BAA6B,MAAM,OAAO;AACxD,WAAO,CAAC;AAAA,EACV;AACF;AAKA,eAAsB,iBACpB,QAC0B;AAC1B,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,MAAM,QAAQ,IAAI;AAAA,IACpB,kBAAkB,MAAM;AAAA,IACxB,yBAAyB,MAAM;AAAA,IAC/B,cAAc,MAAM;AAAA,IACpB,iBAAiB,MAAM;AAAA,IACvB,oBAAoB,MAAM;AAAA,IAC1B,aAAa,MAAM;AAAA,EACrB,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AD9UA,eAAsB,QAAQ,SAAwC;AACpE,QAAM,YAAY,KAAK,IAAI;AAE3B,EAAM;AAAA,IACJC,IAAG;AAAA,MACD,QAAQ,UACJ,0BACA;AAAA,IACN;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,mBAAmB;AAGxC,QAAM,mBAAmB,MAAM,SAAS;AAAA,IACtC;AAAA,IACA,YAAY,MAAM,sBAAsB;AAAA,EAC1C;AAEA,MAAI,kBAAkB;AACpB,aAAS,KAAK,wCAAwC;AAAA,EACxD;AAGA,QAAM,WAAW,MAAM,SAAS;AAAA,IAC9B;AAAA,IACA,YAAY,uBAAuB;AAAA,EACrC;AAEA,WAAS,KAAK,6BAA6BA,IAAG,KAAK,SAAS,SAAS,CAAC,EAAE;AAGxE,MAAI,SAAS,QAAQ;AACrB,MAAI,CAAC,QAAQ;AACX,UAAM,gBAAgB,MAAM,aAAa;AACzC,aAAS,MAAM,aAAa,aAAa;AAAA,EAC3C;AAGA,QAAM,qBAAqB,MAAM;AAAA,IAC/B,SAAS;AAAA,IACT;AAAA,EACF;AACA,MAAI,oBAAoB;AACtB,IAAM,WAAI;AAAA,MACR,yCAAyCA,IAAG,KAAK,SAAS,SAAS,CAAC,cAAcA,IAAG,KAAK,MAAM,CAAC;AAAA,IACnG;AACA,IAAM,WAAI,KAAK,YAAY,mBAAmB,SAAS,EAAE;AACzD,IAAM,WAAI,KAAK,OAAOA,IAAG,KAAK,cAAc,CAAC,wBAAwB;AACrE,IAAM,WAAI,KAAK,OAAOA,IAAG,KAAK,eAAe,CAAC,uBAAuB;AACrE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,OAAO,MAAM,SAAS;AAAA,IAC1B;AAAA,IACA,YAAY,iBAAiB,MAAM;AAAA,EACrC;AAGA,WAAS;AAAA,IACP,UAAU,KAAK,WAAW,MAAM,gBAAgB,KAAK,kBAAkB,MAAM;AAAA,EAC/E;AAGA,MAAI,KAAK,WAAW,WAAW,GAAG;AAChC,IAAM,WAAI,KAAK,yCAAyC;AACxD,IAAM,WAAI;AAAA,MACR,OAAOA,IAAG,KAAK,kBAAkB,CAAC;AAAA,IACpC;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,qBAAqB,KAAK,WAAW,OAAO,CAAC,OAAO,GAAG,QAAQ;AACrE,MAAI,mBAAmB,SAAS,GAAG;AACjC,aAAS;AAAA,MACP,wBAAwB,mBAAmB,IAAI,CAAC,OAAOA,IAAG,KAAK,GAAG,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,IACrF;AAAA,EACF;AAGA,MAAI,WAAW,QAAQ;AACvB,MAAI,CAAC,UAAU;AACb,eAAW,MAAM,eAAe;AAAA,EAClC;AAGA,MAAI;AACJ,MAAI,aAAa,UAAU;AACzB,mBAAe,MAAM,mBAAmB;AAAA,EAC1C;AAGA,QAAM,qBAAqB,MAAM;AAAA,IAC/B,KAAK,WAAW,IAAI,CAAC,QAAQ;AAAA,MAC3B,MAAM,GAAG;AAAA,MACT,UAAU,GAAG;AAAA,IACf,EAAE;AAAA,EACJ;AAEA,MAAI,mBAAmB,WAAW,GAAG;AACnC,IAAM,WAAI,KAAK,6CAA6C;AAC5D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,SAAS,MAAM,mBAAmB;AACxC,QAAM,cACJ,WAAW,WACP,MAAM,gEAAwC;AAAA,IAAK,CAAC,MAClD,EAAE,mBAAmB;AAAA,EACvB,IACA,UAAU,MAAM;AAItB,QAAM,mBAAmB,mBAAmB,OAAO,CAAC,OAAO,CAAC,GAAG,SAAS,GAAG,CAAC;AAC5E,MAAI,iBAAiB,SAAS,GAAG;AAC/B,gBAAY,SAAS,iBAAiB,CAAC;AAAA,EACzC;AAGA,MAAI,EAAE,QAAQ,OAAO,QAAQ,UAAU;AACrC,UAAM,YAAY,MAAM,eAAe;AACvC,QAAI,CAAC,WAAW;AACd,MAAM,cAAO,uBAAuB;AACpC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAGA,QAAM,cAAgC;AAAA,IACpC;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,EACF;AAGA,MAAI,QAAQ,SAAS;AAEnB,QAAI;AACF,YAAM,gBAAgB,MAAM,SAAS;AAAA,QACnC;AAAA,QACA,YAAY;AACV,gBAAM,oBAAoB;AAE1B,gBAAM,QACJ,MAAa,mBAAW,eAAe;AAAA,YACrC;AAAA,cACE,WAAW,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,cAChD,aAAa;AAAA,cACb,SAAS,YAAY;AACnB,sBAAMC,UAAS,MAAM,iBAAiB,WAAW;AACjD,uBAAO;AAAA,kBACL,SAASA,QAAO;AAAA,kBAChB,eAAeA,QAAO;AAAA,kBACtB,WAAWA,QAAO;AAAA,kBAClB,QAAQA,QAAO;AAAA,kBACf,iBAAiBA,QAAO;AAAA,kBACxB,QAAQA,QAAO;AAAA,kBACf,YAAYA,QAAO;AAAA,kBACnB,sBAAsBA,QAAO;AAAA,gBAC/B;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,SAAS,iBAAiB;AAAA,cAC1B,SAAS;AAAA,gBACP,0BAA0B;AAAA,gBAC1B,YAAY;AAAA,cACd;AAAA,cACA,iBAAiB;AAAA,YACnB;AAAA,UACF;AAEF,gBAAM,MAAM,UAAU,cAAc,EAAE,OAAO,OAAO,CAAC;AAGrD,gBAAM,SAAS,MAAM,MAAM,QAAQ,EAAE,MAAM,KAAK,CAAC;AACjD,iBAAO;AAAA,QACT;AAAA,MACF;AAGA,qBAAe;AAAA,QACb,eAAe,cAAc;AAAA,QAC7B,aAAa;AAAA,MACf,CAAC;AAED,MAAM;AAAA,QACJD,IAAG,MAAM,qDAAqD;AAAA,MAChE;AAGA,uBAAiB,SAAS,MAAM;AAAA,QAC9B;AAAA,QACA;AAAA,QACA,SAAS;AAAA,QACT,aAAa,KAAK,IAAI,IAAI;AAAA,QAC1B,qBAAqB,mBAAmB;AAAA,MAC1C,CAAC;AACD;AAAA,IACF,SAAS,OAAY;AACnB,iBAAW,kBAAkB,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACjE,UAAI,MAAM,SAAS,SAAS,2BAA2B,GAAG;AACxD,cAAM,OAAO,YAAY;AAAA,MAC3B;AACA,YAAM,IAAI,MAAM,mBAAmB,MAAM,OAAO,EAAE;AAAA,IACpD;AAAA,EACF;AAGA,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,SAAS;AAAA,MACvB;AAAA,MACA,YAAY;AACV,cAAM,oBAAoB;AAE1B,cAAM,QACJ,MAAa,mBAAW,eAAe;AAAA,UACrC;AAAA,YACE,WAAW,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,YAChD,aAAa;AAAA,YACb,SAAS,YAAY;AACnB,oBAAM,SAAS,MAAM,iBAAiB,WAAW;AAEjD,qBAAO;AAAA,gBACL,SAAS,OAAO;AAAA,gBAChB,eAAe,OAAO;AAAA,gBACtB,WAAW,OAAO;AAAA,gBAClB,QAAQ,OAAO;AAAA,gBACf,iBAAiB,OAAO;AAAA,gBACxB,QAAQ,OAAO;AAAA,gBACf,YAAY,OAAO;AAAA,gBACnB,sBAAsB,OAAO;AAAA,cAC/B;AAAA,YACF;AAAA,UACF;AAAA,UACA;AAAA,YACE,SAAS,iBAAiB;AAAA,YAC1B,SAAS;AAAA,cACP,0BAA0B;AAAA,cAC1B,YAAY;AAAA,YACd;AAAA,YACA,iBAAiB;AAAA,UACnB;AAAA,QACF;AAEF,cAAM,MAAM,UAAU;AAAA,UACpB,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,QACvC;AACA,cAAM,MAAM,UAAU,cAAc,EAAE,OAAO,OAAO,CAAC;AAErD,cAAM,WAAW,MAAM,MAAM,GAAG,EAAE,UAAU,MAAM;AAAA,QAAC,EAAE,CAAC;AACtD,cAAM,gBAAgB,SAAS;AAE/B,eAAO;AAAA,UACL,SAAS,cAAc,SAAS;AAAA,UAChC,eAAe,cAAc,eAAe;AAAA,UAG5C,WAAW,cAAc,WAAW;AAAA,UACpC,QAAQ,cAAc,QAAQ;AAAA,UAC9B,iBAAiB,cAAc,iBAAiB;AAAA,UAGhD,QAAQ,cAAc,QAAQ;AAAA,UAC9B,YAAY,cAAc,YAAY;AAAA,UACtC,sBAAsB,cAAc,sBAAsB;AAAA,QAG5D;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAY;AAEnB,qBAAiB,SAAS,OAAO;AAAA,MAC/B;AAAA,MACA;AAAA,MACA,aAAa,KAAK,IAAI,IAAI;AAAA,IAC5B,CAAC;AAGD,QAAI,MAAM,SAAS,SAAS,2BAA2B,GAAG;AACxD,iBAAW,gBAAgB,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC9D,YAAM,OAAO,YAAY;AAAA,IAC3B;AAEA,eAAW,qBAAqB,iBAAiB,EAAE,MAAM,SAAS,CAAC;AACnE,UAAM,IAAI,MAAM,6BAA6B,MAAM,OAAO,EAAE;AAAA,EAC9D;AAGA,MAAI,QAAQ,UAAU,QAAQ,cAAc,QAAQ,WAAW,SAAS,GAAG;AACzE,UAAM,EAAE,gBAAAE,iBAAgB,kBAAAC,kBAAiB,IAAI,MAAM;AAGnD,UAAM,aAAa,MAAMD,gBAAe,QAAQ,QAAQ,MAAM;AAE9D,QAAI,YAAY;AACd,UAAI;AACF,iBAAS,MAAM,iCAAiC;AAGhD,cAAM,iBACJ,YAAY,kBAAkB,QAAQ,QAAQ,MAAM;AAEtD,cAAMC;AAAA,UACJ,WAAW;AAAA,UACX,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ;AAAA,UACR;AAAA,QACF;AACA,iBAAS,QAAQ,gCAAgC;AAAA,MACnD,SAAS,OAAY;AACnB,iBAAS;AAAA,UACP,+CAA+C,MAAM,OAAO;AAAA,QAC9D;AACA,iBAAS;AAAA,UACP;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW;AAAA,IACf,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,WAAW,SAAY;AAAA,EACpC;AACA,MAAI,SAAS,SAAS,OAAO;AAC3B,aAAS,SAAS,MAAM,kBAAkB,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,EACjF;AACA,MAAI,cAAc;AAChB,aAAS,SAAS;AAAA,EACpB;AACA,QAAM,uBAAuB,QAAQ;AAErC,WAAS,KAAK,2BAA2B;AAGzC,iBAAe;AAAA,IACb,SAAS,QAAQ;AAAA,IACjB,eAAe,QAAQ;AAAA,IACvB,QAAQ,QAAQ;AAAA,IAChB,WAAW,QAAQ;AAAA,EACrB,CAAC;AAGD,MAAI,mBAAmB,SAAS,KAAK,YAAY,UAAU,SAAS;AAClE,YAAQ,IAAI;AAAA,EAAKH,IAAG,KAAK,aAAa,CAAC;AAAA,CAAI;AAC3C,YAAQ;AAAA,MACN,8CAA8CA,IAAG,KAAK,sBAAsB,CAAC;AAAA,IAC/E;AACA,YAAQ,IAAI;AAAA,EAAKA,IAAG,IAAI,UAAU,CAAC,EAAE;AACrC,YAAQ;AAAA,MACNA,IAAG,KAAK;AAAA;AAAA;AAAA,MAGR;AAAA,IACF;AACA,YAAQ,IAAI,EAAE;AAAA,EAChB;AAGA,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,QAAM,kBAA4B,CAAC;AACnC,MAAI,YAAY,UAAU,QAAS,iBAAgB,KAAK,UAAU;AAClE,MAAI,YAAY,iBAAiB;AAC/B,oBAAgB,KAAK,kBAAkB;AACzC,MAAI,YAAY,eAAe;AAC7B,oBAAgB,KAAK,gBAAgB;AACvC,MAAI,YAAY,eAAe;AAC7B,oBAAgB,KAAK,kBAAkB;AAEzC,mBAAiB,SAAS,MAAM;AAAA,IAC9B;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,aAAa;AAAA,IACb,qBAAqB,mBAAmB;AAAA,EAC1C,CAAC;AAED,uBAAqB,SAAS;AAAA,IAC5B,aAAa;AAAA,IACb,UAAU;AAAA,IACV;AAAA,EACF,CAAC;AACH;;;AExbA;AAGA;AAKA;AARA,YAAYI,YAAW;AACvB,YAAYC,aAAY;AACxB,OAAOC,SAAQ;;;ACFf;AAAA;AAAA,EAEE,mCAAAC;AAAA,EACA,gCAAAC;AAAA,EACA;AAAA,EACA,iBAAAC;AAAA,OACK;AAsFP,eAAsBC,gBACpB,QACA,QAC8C;AAC9C,QAAM,SAAS,IAAIC,eAAc,EAAE,OAAO,CAAC;AAE3C,MAAI;AACF,UAAM,WAAW,MAAM,OAAO;AAAA,MAC5B,IAAIC,8BAA6B;AAAA,QAC/B,SAAS;AAAA,QACT,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AAEA,UAAM,OAAO,SAAS,cAAc,CAAC;AACrC,QAAI,QAAQ,KAAK,SAAS,GAAG,MAAM,OAAO,KAAK,IAAI;AACjD,aAAO;AAAA,QACL,IAAI,KAAK,GAAG,QAAQ,gBAAgB,EAAE;AAAA,QACtC,MAAM,KAAK;AAAA,MACb;AAAA,IACF;AAEA,WAAO;AAAA,EACT,SAAS,QAAQ;AACf,WAAO;AAAA,EACT;AACF;AAyIA,eAAsB,iBACpB,cACA,QACA,YACA,QACA,sBACA,gBACe;AACf,QAAM,SAAS,IAAIC,eAAc,EAAE,OAAO,CAAC;AAI3C,QAAM,WAAW,MAAM,OAAO;AAAA,IAC5B,IAAI,8BAA8B;AAAA,MAChC,cAAc;AAAA,MACd,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,QAAM,aAAa,SAAS,sBAAsB,CAAC;AACnD,QAAM,UAAoB,CAAC;AAG3B,QAAM,sBAAsB,CAAC,MAAc,SAAiB;AAE1D,UAAM,iBAAiB,KAAK,SAAS,GAAG,IAAI,OAAO,GAAG,IAAI;AAC1D,UAAM,SAAS,WAAW;AAAA,MACxB,CAAC,OAAO,GAAG,SAAS,kBAAkB,GAAG,SAAS;AAAA,IACpD;AACA,QAAI,UAAU,OAAO,iBAAiB;AACpC,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,mBAAmB;AAAA,MACrB,CAAC;AAAA,IACH;AAAA,EACF;AAGA,aAAW,SAAS,YAAY;AAC9B,wBAAoB,GAAG,KAAK,eAAe,MAAM,IAAI,OAAO;AAAA,EAC9D;AAGA,sBAAoB,UAAU,MAAM,IAAI,KAAK;AAG7C,MAAI,sBAAsB;AACxB,wBAAoB,sBAAsB,OAAO;AAAA,EACnD;AAGA,MAAI,gBAAgB;AAClB,wBAAoB,gBAAgB,IAAI;AACxC,wBAAoB,gBAAgB,KAAK;AAAA,EAC3C;AAMA,MAAI,QAAQ,WAAW,GAAG;AACxB;AAAA,EACF;AAEA,QAAM,OAAO;AAAA,IACX,IAAIC,iCAAgC;AAAA,MAClC,cAAc;AAAA,MACd,aAAa;AAAA,QACX,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;AD1SA,eAAe,qBACb,QACA,QACmB;AACnB,MAAI;AACF,UAAM,EAAE,aAAAC,cAAa,yBAAAC,yBAAwB,IAAI,MAAM,OACrD,uBACF;AACA,UAAM,MAAM,IAAID,aAAY,EAAE,OAAO,CAAC;AAEtC,UAAM,WAAW,MAAM,IAAI;AAAA,MACzB,IAAIC,yBAAwB,EAAE,eAAe,OAAO,CAAC;AAAA,IACvD;AAEA,WAAO,SAAS,gBAAgB,UAAU,CAAC;AAAA,EAC7C,SAAS,QAAQ;AACf,WAAO,CAAC;AAAA,EACV;AACF;AAKA,eAAsB,aAAa,SAAwC;AACzE,QAAM,YAAY,KAAK,IAAI;AAE3B,EAAM;AAAA,IACJC,IAAG;AAAA,MACD,QAAQ,UACJ,6CACA;AAAA,IACN;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,mBAAmB;AAGxC,QAAM,WAAW,MAAM,SAAS;AAAA,IAC9B;AAAA,IACA,YAAY,uBAAuB;AAAA,EACrC;AAGA,QAAM,SAAS,MAAM,aAAa;AAGlC,QAAM,WAAW,MAAM,uBAAuB,SAAS,WAAW,MAAM;AACxE,QAAM,eAAe,UAAU,UAAU;AACzC,QAAM,cAAc,cAAc;AAClC,QAAM,SAAS,aAAa;AAC5B,QAAM,kBAAkB,cAAc;AAGtC,MAAI,EAAE,QAAQ,SAAS,QAAQ,UAAU;AACvC,UAAM,YAAY,MAAY,eAAQ;AAAA,MACpC,SAASA,IAAG;AAAA,QACV;AAAA,MACF;AAAA,MACA,cAAc;AAAA,IAChB,CAAC;AAED,QAAU,gBAAS,SAAS,KAAK,CAAC,WAAW;AAC3C,MAAM,cAAO,wBAAwB;AACrC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAGA,MAAI,iBAAiB;AACrB,MAAI,aAAkD;AACtD,MAAI,aAAuB,CAAC;AAE5B,MAAI,UAAU,CAAC,QAAQ,SAAS;AAC9B,iBAAa,MAAMC,gBAAe,QAAQ,MAAM;AAEhD,QAAI,YAAY;AAEd,mBAAa,MAAM,qBAAqB,QAAQ,MAAM;AAEtD,UAAI,CAAC,QAAQ,OAAO;AAClB,cAAM,WAAW,MAAY,eAAQ;AAAA,UACnC,SAAS,iCAAiCD,IAAG,KAAK,MAAM,CAAC;AAAA,UACzD,cAAc;AAAA,QAChB,CAAC;AAED,YAAU,gBAAS,QAAQ,GAAG;AAC5B,UAAM,cAAO,wBAAwB;AACrC,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAEA,yBAAiB;AAAA,MACnB,OAAO;AACL,yBAAiB;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAGA,MAAI,QAAQ,SAAS;AAEnB,QAAI;AACF,YAAM,gBAAgB,MAAM,SAAS;AAAA,QACnC;AAAA,QACA,YAAY;AACV,gBAAM,oBAAoB;AAG1B,gBAAM,YACJ,mBAAmB,eAAe,SAAS,SAAS,IAAI,MAAM;AAGhE,cAAI;AACJ,cAAI;AACF,oBAAQ,MAAa,mBAAW,eAAe,YAAY;AAAA,cACzD;AAAA,cACA,SAAS,iBAAiB;AAAA,YAC5B,CAAC;AAAA,UACH,SAAS,QAAQ;AACf,kBAAM,IAAI,MAAM,0CAA0C;AAAA,UAC5D;AAGA,gBAAM,SAAS,MAAM,MAAM,QAAQ,EAAE,MAAM,KAAK,CAAC;AACjD,iBAAO;AAAA,QACT;AAAA,MACF;AAGA,qBAAe;AAAA,QACb,eAAe,cAAc;AAAA,QAC7B,cAAc;AAAA,QACd,aAAa;AAAA,MACf,CAAC;AAGD,UAAI,QAAQ;AACV,cAAM,oBAAoB,MAAMC,gBAAe,QAAQ,MAAM;AAC7D,YAAI,mBAAmB;AACrB,UAAM,WAAI;AAAA,YACR,8BAA8BD,IAAG,KAAK,MAAM,CAAC;AAAA,UAC/C;AAAA,QACF;AAAA,MACF;AAEA,MAAM;AAAA,QACJA,IAAG,MAAM,qDAAqD;AAAA,MAChE;AAGA,0BAAoB,SAAS;AAAA,QAC3B,SAAS;AAAA,QACT,aAAa,KAAK,IAAI,IAAI;AAAA,MAC5B,CAAC;AACD;AAAA,IACF,SAAS,OAAY;AACnB,eAAS,KAAK;AACd,UAAI,MAAM,QAAQ,SAAS,+BAA+B,GAAG;AAC3D,QAAM,WAAI,KAAK,0CAA0C;AACzD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,iBAAW,kBAAkB,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACjE,YAAM,IAAI,MAAM,mBAAmB,MAAM,OAAO,EAAE;AAAA,IACpD;AAAA,EACF;AAKA,MAAI,kBAAkB,cAAc,UAAU,WAAW,SAAS,GAAG;AACnE,QAAI;AACF,YAAM,SAAS;AAAA,QACb,4BAA4B,MAAM;AAAA,QAClC,YAAY;AACV,gBAAM;AAAA,YACJ,WAAW;AAAA,YACX;AAAA,YACA;AAAA,YACA;AAAA,YACA,aAAa,UAAU;AAAA,YACvB,aAAa;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAY;AACnB,MAAM,WAAI,KAAK,iCAAiC,MAAM,OAAO,EAAE;AAC/D,MAAM,WAAI,KAAK,mDAAmD;AAAA,IACpE;AAAA,EACF;AAGA,MAAI;AACF,UAAM,SAAS;AAAA,MACb;AAAA,MACA,YAAY;AAEV,cAAM,oBAAoB;AAG1B,cAAM,YACJ,mBAAmB,eAAe,SAAS,SAAS,IAAI,MAAM;AAGhE,YAAI;AACJ,YAAI;AACF,kBAAQ,MAAa,mBAAW,eAAe,YAAY;AAAA,YACzD;AAAA,YACA,SAAS,iBAAiB;AAAA,UAC5B,CAAC;AAAA,QACH,SAAS,QAAQ;AACf,gBAAM,IAAI,MAAM,0CAA0C;AAAA,QAC5D;AAGA,cAAM,MAAM,QAAQ,EAAE,UAAU,MAAM;AAAA,QAAC,EAAE,CAAC;AAG1C,cAAM,MAAM,UAAU,YAAY,SAAS;AAAA,MAC7C;AAAA,IACF;AAAA,EACF,SAAS,OAAY;AACnB,aAAS,KAAK;AACd,QAAI,MAAM,QAAQ,SAAS,+BAA+B,GAAG;AAC3D,MAAM,WAAI,KAAK,+BAA+B;AAE9C,YAAM,yBAAyB,SAAS,WAAW,MAAM;AACzD,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,eAAW,kBAAkB,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACjE,IAAM,WAAI,MAAM,yCAAyC;AACzD,UAAM;AAAA,EACR;AAGA,QAAM,yBAAyB,SAAS,WAAW,MAAM;AAGzD,WAAS,KAAK;AAEd,QAAM,eAAe,CAAC,oBAAoB;AAC1C,MAAI,kBAAkB,YAAY;AAChC,iBAAa,KAAK,qBAAqB;AAAA,EACzC;AAEA,EAAM,aAAMA,IAAG,MAAM,uCAAuC,CAAC;AAE7D,MAAI,QAAQ;AACV,YAAQ,IAAI;AAAA,EAAKA,IAAG,KAAK,aAAa,CAAC,EAAE;AACzC,eAAW,QAAQ,cAAc;AAC/B,cAAQ,IAAI,KAAKA,IAAG,MAAM,QAAG,CAAC,IAAI,IAAI,EAAE;AAAA,IAC1C;AAGA,YAAQ;AAAA,MACN;AAAA,EAAKA,IAAG,IAAI,sFAAsF,CAAC;AAAA,IACrG;AAAA,EACF;AAEA,UAAQ;AAAA,IACN;AAAA,MAASA,IAAG,KAAK,kBAAkB,CAAC;AAAA;AAAA,EACtC;AAGA,sBAAoB,SAAS;AAAA,IAC3B,QAAQ;AAAA,IACR,aAAa,KAAK,IAAI,IAAI;AAAA,IAC1B,aAAa;AAAA,EACf,CAAC;AACH;;;AExSA;AAIA;AAEA;AANA,SAAS,gBAAgB;AACzB,SAAS,yBAAyB,eAAAE,oBAAmB;AACrD,YAAYC,YAAW;AACvB,OAAOC,SAAQ;AASf,eAAsB,aAAa,SAA4C;AAC7E,EAAM,aAAMC,IAAG,KAAK,aAAa,QAAQ,MAAM,EAAE,CAAC;AAElD,QAAM,WAAW,IAAI,mBAAmB;AACxC,QAAM,SAAS,MAAM,aAAa;AAGlC,QAAM,YAAY,IAAIC,aAAY,EAAE,OAAO,CAAC;AAC5C,MAAI;AACJ,MAAI,aAAuB,CAAC;AAC5B,MAAI;AAEJ,MAAI;AACF,eAAW,MAAM,SAAS;AAAA,MACxB;AAAA,MACA,YAAY;AACV,cAAM,WAAW,MAAM,UAAU;AAAA,UAC/B,IAAI,wBAAwB,EAAE,eAAe,QAAQ,OAAO,CAAC;AAAA,QAC/D;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAEA,iBAAa,SAAS,gBAAgB,UAAU,CAAC;AACjD,qBAAiB,SAAS,oBAAoB;AAAA,EAChD,SAAS,QAAa;AACpB,aAAS,KAAK;AACd,IAAM,WAAI,MAAM,UAAU,QAAQ,MAAM,mBAAmB;AAC3D,YAAQ;AAAA,MACN;AAAA,MAASD,IAAG,KAAK,6BAA6B,QAAQ,MAAM,EAAE,CAAC;AAAA;AAAA,IACjE;AACA,YAAQ,KAAK,CAAC;AACd;AAAA,EACF;AAGA,QAAM,WAAW,IAAI,SAAS;AAE9B,WAAS,WAAW,CAAC,WAAW,SAAS,CAAC;AAC1C,QAAM,aAKD,CAAC;AAGN,aAAW,SAAS,YAAY;AAC9B,UAAM,aAAa,GAAG,KAAK,eAAe,QAAQ,MAAM;AACxD,QAAI;AACF,YAAM,UAAU,MAAM,SAAS,aAAa,UAAU;AACtD,YAAM,WAAW,GAAG,KAAK;AACzB,YAAM,QAAQ,QAAQ,KAAK,CAAC,MAAM,MAAM,YAAY,MAAM,GAAG,QAAQ,GAAG;AACxE,iBAAW,KAAK;AAAA,QACd,MAAM;AAAA,QACN,MAAM;AAAA,QACN,QAAQ,QAAQ,aAAa;AAAA,QAC7B;AAAA,MACF,CAAC;AAAA,IACH,SAAS,QAAQ;AACf,iBAAW,KAAK;AAAA,QACd,MAAM;AAAA,QACN,MAAM;AAAA,QACN,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,WAAW,QAAQ,MAAM;AACxD,UAAM,YAAY,QAAQ,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,QAAQ,CAAC;AACnE,UAAM,eAAe,WAAW,SAAS,uBAAuB;AAChE,eAAW,KAAK;AAAA,MACd,MAAM,QAAQ;AAAA,MACd,MAAM;AAAA,MACN,QAAQ,eAAe,aAAa,YAAY,cAAc;AAAA,MAC9D,SAAS,YAAY,CAAC,SAAS,IAAI;AAAA,IACrC,CAAC;AAAA,EACH,SAAS,QAAQ;AACf,eAAW,KAAK;AAAA,MACd,MAAM,QAAQ;AAAA,MACd,MAAM;AAAA,MACN,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAGA,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,WAAW,UAAU,QAAQ,MAAM,EAAE;AACpE,UAAM,cAAc,QAAQ,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,UAAU,CAAC;AACvE,eAAW,KAAK;AAAA,MACd,MAAM,UAAU,QAAQ,MAAM;AAAA,MAC9B,MAAM;AAAA,MACN,QAAQ,cAAc,aAAa;AAAA,MACnC,SAAS,cAAc,CAAC,WAAW,IAAI;AAAA,IACzC,CAAC;AAAA,EACH,SAAS,QAAQ;AACf,eAAW,KAAK;AAAA,MACd,MAAM,UAAU,QAAQ,MAAM;AAAA,MAC9B,MAAM;AAAA,MACN,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAGA,MAAI,gBAAgB;AAElB,QAAI;AACF,YAAM,YAAY,MAAM,SAAS,UAAU,cAAc;AACzD,YAAM,aAAa,iBAAiB,MAAM;AAC1C,YAAM,QAAQ,UAAU;AAAA,QACtB,CAAC,MAAM,EAAE,aAAa,cAAc,EAAE,aAAa,GAAG,UAAU;AAAA,MAClE;AACA,iBAAW,KAAK;AAAA,QACd,MAAM;AAAA,QACN,MAAM;AAAA,QACN,QAAQ,QACJ,aACA,UAAU,SAAS,IACjB,cACA;AAAA,QACN,SAAS,UAAU,IAAI,CAAC,MAAM,GAAG,EAAE,QAAQ,IAAI,EAAE,QAAQ,EAAE;AAAA,MAC7D,CAAC;AAAA,IACH,SAAS,QAAQ;AACf,iBAAW,KAAK;AAAA,QACd,MAAM;AAAA,QACN,MAAM;AAAA,QACN,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAGA,QAAI;AACF,YAAM,UAAU,MAAM,SAAS,WAAW,cAAc;AACxD,YAAM,YAAY,QAAQ,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,QAAQ,CAAC;AACnE,YAAM,eAAe,WAAW,SAAS,uBAAuB;AAChE,iBAAW,KAAK;AAAA,QACd,MAAM;AAAA,QACN,MAAM;AAAA,QACN,QAAQ,eAAe,aAAa,YAAY,cAAc;AAAA,QAC9D,SAAS,YAAY,CAAC,SAAS,IAAI;AAAA,MACrC,CAAC;AAAA,IACH,SAAS,QAAQ;AACf,iBAAW,KAAK;AAAA,QACd,MAAM;AAAA,QACN,MAAM;AAAA,QACN,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AAEA,WAAS,KAAK;AAGd,QAAM,qBAAqB,SAAS,2BAChC,aACA;AACJ,QAAM,aAAa,SAAS,gBAAgB,UAAU;AACtD,QAAM,iBACJ,SAAS,oBAAoB,wBAAwB;AAEvD,QAAM,cAAc;AAAA,IAClB,GAAGA,IAAG,KAAK,SAAS,CAAC,IAAI,QAAQ,MAAM;AAAA,IACvC,GAAGA,IAAG,KAAK,sBAAsB,CAAC,IAChC,uBAAuB,aACnBA,IAAG,MAAM,iBAAY,IACrBA,IAAG,OAAO,gBAAW,CAC3B;AAAA,IACA,GAAGA,IAAG,KAAK,cAAc,CAAC,IACxB,eAAe,YACXA,IAAG,MAAM,gBAAW,IACpBA,IAAG,OAAO,UAAK,UAAU,EAAE,CACjC;AAAA,EACF;AAEA,MAAI,gBAAgB;AAClB,gBAAY;AAAA,MACV,GAAGA,IAAG,KAAK,mBAAmB,CAAC,IAAI,cAAc;AAAA,MACjD,GAAGA,IAAG,KAAK,mBAAmB,CAAC,IAC7B,mBAAmB,YACfA,IAAG,MAAM,gBAAW,IACpB,mBAAmB,mBACjBA,IAAG,OAAO,uBAAkB,IAC5BA,IAAG,OAAO,UAAK,cAAc,EAAE,CACvC;AAAA,IACF;AAAA,EACF;AAEA,EAAM,YAAK,YAAY,KAAK,IAAI,GAAG,YAAY;AAG/C,QAAM,WAAW,WAAW,IAAI,CAAC,WAAW;AAC1C,QAAI;AACJ,QAAI;AAEJ,QAAI,OAAO,WAAW,YAAY;AAChC,mBAAa;AACb,oBAAcA,IAAG;AAAA,IACnB,WAAW,OAAO,WAAW,aAAa;AACxC,mBAAa;AACb,oBAAcA,IAAG;AAAA,IACnB,OAAO;AACL,mBAAa;AACb,oBAAcA,IAAG;AAAA,IACnB;AAEA,UAAM,aAAa,OAAO,UAAU,WAAM,OAAO,QAAQ,KAAK,IAAI,CAAC,KAAK;AACxE,WAAO,KAAK,YAAY,UAAU,CAAC,IAAI,OAAO,IAAI,KAAK,OAAO,IAAI,KAAK;AAAA,MACrE,OAAO;AAAA,IACT,CAAC,GAAG,UAAU;AAAA,EAChB,CAAC;AAED,EAAM,YAAK,SAAS,KAAK,IAAI,GAAG,aAAa;AAG7C,QAAM,cAAc,WAAW,MAAM,CAAC,MAAM,EAAE,WAAW,UAAU;AACnE,QAAM,gBAAgB,WAAW,KAAK,CAAC,MAAM,EAAE,WAAW,WAAW;AAErE,MAAI,uBAAuB,cAAc,aAAa;AACpD,IAAM;AAAA,MACJA,IAAG,MAAM,2DAAsD;AAAA,IACjE;AACA,iBAAa,mBAAmB,EAAE,mBAAmB,KAAK,CAAC;AAAA,EAC7D,WAAW,eAAe;AACxB,IAAM;AAAA,MACJA,IAAG,IAAI,4DAAuD;AAAA,IAChE;AACA,YAAQ;AAAA,MACN;AAAA,MAASA,IAAG,KAAK,oBAAoB,CAAC;AAAA;AAAA,IACxC;AAAA,EACF,OAAO;AACL,IAAM;AAAA,MACJA,IAAG,OAAO,yDAAoD;AAAA,IAChE;AACA,YAAQ,IAAI,qDAAqD;AACjE,YAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAGA,eAAa,wBAAwB;AAAA,IACnC,SAAS;AAAA,IACT,UAAU,uBAAuB,cAAc;AAAA,IAC/C,aAAa;AAAA,EACf,CAAC;AACH;AAKA,eAAsB,UAAU,SAA4C;AAC1E,EAAM,aAAMA,IAAG,KAAK,iBAAiB,QAAQ,MAAM,SAAS,CAAC;AAE7D,QAAM,WAAW,IAAI,mBAAmB;AACxC,QAAM,SAAS,MAAM,aAAa;AAClC,QAAM,YAAY,IAAIC,aAAY,EAAE,OAAO,CAAC;AAE5C,MAAI;AAEF,QAAI;AACF,YAAM,UAAU;AAAA,QACd,IAAI,wBAAwB,EAAE,eAAe,QAAQ,OAAO,CAAC;AAAA,MAC/D;AACA,eAAS,KAAK;AACd,MAAM,WAAI,KAAK,UAAU,QAAQ,MAAM,wBAAwB;AAC/D,cAAQ;AAAA,QACN;AAAA,MAASD,IAAG,KAAK,uCAAuC,QAAQ,MAAM,EAAE,CAAC;AAAA;AAAA,MAC3E;AACA;AAAA,IACF,SAAS,OAAY;AAEnB,UAAI,MAAM,SAAS,qBAAqB;AACtC,cAAM;AAAA,MACR;AAAA,IACF;AAGA,UAAM,EAAE,2BAA2B,IAAI,MAAM,OAC3C,uBACF;AACA,UAAM,SAAS,QAAQ,wBAAwB,YAAY;AACzD,YAAM,UAAU;AAAA,QACd,IAAI,2BAA2B;AAAA,UAC7B,eAAe,QAAQ;AAAA,UACvB,uBAAuB;AAAA,YACrB,sBAAsB;AAAA,UACxB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAGD,UAAM,WAAW,MAAM,UAAU;AAAA,MAC/B,IAAI,wBAAwB,EAAE,eAAe,QAAQ,OAAO,CAAC;AAAA,IAC/D;AACA,UAAM,aAAa,SAAS,gBAAgB,UAAU,CAAC;AAEvD,aAAS,KAAK;AAEd,IAAM,aAAMA,IAAG,MAAM,iBAAY,QAAQ,MAAM,sBAAsB,CAAC;AAGtE,YAAQ,IAAI;AAAA,EAAKA,IAAG,KAAK,aAAa,CAAC;AAAA,CAAI;AAC3C,YAAQ,IAAI,kDAAkD;AAE9D,eAAW,SAAS,YAAY;AAC9B,cAAQ,IAAI,MAAMA,IAAG,KAAK,GAAG,KAAK,eAAe,QAAQ,MAAM,EAAE,CAAC,EAAE;AACpE,cAAQ;AAAA,QACN,MAAMA,IAAG,IAAI,OAAO,CAAC,WAAWA,IAAG,IAAI,QAAQ,CAAC,IAAI,KAAK;AAAA;AAAA,MAC3D;AAAA,IACF;AAEA,YAAQ;AAAA,MACN,8BAA8BA,IAAG,KAAK,uCAAuC,QAAQ,MAAM,EAAE,CAAC;AAAA,IAChG;AACA,YAAQ,IAAI,oBAAoBA,IAAG,KAAK,oBAAoB,CAAC;AAAA,CAAI;AAGjE,iBAAa,qBAAqB;AAAA,MAChC,SAAS;AAAA,IACX,CAAC;AACD,iBAAa,gBAAgB,CAAC,CAAC;AAAA,EACjC,SAAS,OAAY;AACnB,aAAS,KAAK;AACd,iBAAa,qBAAqB;AAAA,MAChC,SAAS;AAAA,IACX,CAAC;AACD,UAAM;AAAA,EACR;AACF;AAKA,eAAsB,cAA6B;AACjD,EAAM,aAAMA,IAAG,KAAK,mBAAmB,CAAC;AAExC,QAAM,WAAW,IAAI,mBAAmB;AACxC,QAAM,SAAS,MAAM,aAAa;AAClC,QAAM,YAAY,IAAIC,aAAY,EAAE,OAAO,CAAC;AAE5C,MAAI;AACF,UAAM,EAAE,2BAA2B,IAAI,MAAM,OAC3C,uBACF;AAEA,UAAM,aAAa,MAAM,SAAS;AAAA,MAChC;AAAA,MACA,YAAY;AACV,cAAM,WAAW,MAAM,UAAU;AAAA,UAC/B,IAAI,2BAA2B,CAAC,CAAC;AAAA,QACnC;AACA,eAAO,SAAS,mBAAmB,CAAC;AAAA,MACtC;AAAA,IACF;AAGA,UAAM,UAAU,WAAW;AAAA,MACzB,CAAC,aACC,SAAS,iBAAiB,YACzB,SAAS,gBAAgB,CAAC,SAAS,aAAa,SAAS,GAAG;AAAA,IACjE;AAEA,aAAS,KAAK;AAEd,QAAI,QAAQ,WAAW,GAAG;AACxB,MAAM,aAAM,yBAAyB;AACrC,cAAQ;AAAA,QACN;AAAA,MAASD,IAAG,KAAK,kCAAkC,CAAC;AAAA;AAAA,MACtD;AACA;AAAA,IACF;AAGA,UAAM,gBAAgB,MAAM,QAAQ;AAAA,MAClC,QAAQ,IAAI,OAAO,WAAW;AAC5B,YAAI;AACF,gBAAM,UAAU,MAAM,UAAU;AAAA,YAC9B,IAAI,wBAAwB;AAAA,cAC1B,eAAe,OAAO;AAAA,YACxB,CAAC;AAAA,UACH;AACA,iBAAO;AAAA,YACL,MAAM,OAAO;AAAA,YACb,UAAU,QAAQ;AAAA,YAClB,YAAY,QAAQ,gBAAgB,UAAU;AAAA,UAChD;AAAA,QACF,QAAQ;AACN,iBAAO;AAAA,YACL,MAAM,OAAO;AAAA,YACb,UAAU;AAAA,YACV,YAAY;AAAA,UACd;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAGA,UAAM,cAAc,cAAc,IAAI,CAAC,WAAW;AAChD,YAAM,aAAa,OAAO,WAAWA,IAAG,MAAM,QAAG,IAAIA,IAAG,OAAO,QAAG;AAClE,YAAM,WACJ,OAAO,eAAe,YAAYA,IAAG,MAAM,QAAG,IAAIA,IAAG,OAAO,QAAG;AACjE,aAAO,KAAK,UAAU,IAAIA,IAAG,KAAK,OAAO,IAAI,CAAC,WAAW,QAAQ,IAAI,OAAO,UAAU;AAAA,IACxF,CAAC;AAED,IAAM;AAAA,MACJ,YAAY,KAAK,IAAI;AAAA,MACrB,GAAG,QAAQ,MAAM,iBAAiB,MAAM;AAAA,IAC1C;AACA,IAAM;AAAA,MACJA,IAAG;AAAA,QACD,OAAOA,IAAG,KAAK,8CAA8C,CAAC;AAAA,MAChE;AAAA,IACF;AAGA,iBAAa,sBAAsB;AAAA,MACjC,SAAS;AAAA,MACT,cAAc,QAAQ;AAAA,IACxB,CAAC;AAAA,EACH,SAAS,OAAY;AACnB,aAAS,KAAK;AACd,iBAAa,sBAAsB,EAAE,SAAS,MAAM,CAAC;AACrD,UAAM;AAAA,EACR;AACF;AAKA,eAAsB,QAAQ,SAA4C;AACxE,EAAM,aAAMA,IAAG,KAAK,mBAAmB,QAAQ,MAAM,EAAE,CAAC;AAExD,QAAM,WAAW,IAAI,mBAAmB;AACxC,QAAM,SAAS,MAAM,aAAa;AAClC,QAAM,YAAY,IAAIC,aAAY,EAAE,OAAO,CAAC;AAE5C,MAAI;AACF,UAAM,WAAW,MAAM,SAAS;AAAA,MAC9B;AAAA,MACA,YAAY;AACV,cAAM,WAAW,MAAM,UAAU;AAAA,UAC/B,IAAI,wBAAwB,EAAE,eAAe,QAAQ,OAAO,CAAC;AAAA,QAC/D;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,aAAa,SAAS,gBAAgB,UAAU,CAAC;AACvD,UAAM,aAAa,SAAS,gBAAgB,UAAU;AAEtD,aAAS,KAAK;AAEd,QAAI,WAAW,WAAW,GAAG;AAC3B,MAAM,aAAMD,IAAG,OAAO,sCAAsC,CAAC;AAC7D;AAAA,IACF;AAGA,UAAM,aAAa,GAAGA,IAAG,KAAK,cAAc,CAAC,IAC3C,eAAe,YACXA,IAAG,MAAM,iBAAY,IACrBA,IAAG,OAAO,UAAK,UAAU,EAAE,CACjC;AACA,IAAM,YAAK,YAAY,QAAQ;AAG/B,YAAQ,IAAI;AAAA,EAAKA,IAAG,KAAK,qBAAqB,CAAC;AAAA,CAAI;AACnD,eAAW,SAAS,YAAY;AAC9B,cAAQ,IAAI,GAAGA,IAAG,KAAK,GAAG,KAAK,eAAe,QAAQ,MAAM,EAAE,CAAC,EAAE;AACjE,cAAQ,IAAI,KAAKA,IAAG,IAAI,OAAO,CAAC,QAAQ;AACxC,cAAQ,IAAI,KAAKA,IAAG,IAAI,QAAQ,CAAC,IAAI,KAAK;AAAA,CAAuB;AAAA,IACnE;AAEA,QAAI,eAAe,WAAW;AAC5B,cAAQ;AAAA,QACN,GAAGA,IAAG,IAAI,kCAAkC,CAAC,IAAIA,IAAG,KAAK,uCAAuC,QAAQ,MAAM,EAAE,CAAC;AAAA;AAAA,MACnH;AAAA,IACF;AAGA,iBAAa,0BAA0B;AAAA,MACrC,SAAS;AAAA,MACT,aAAa;AAAA,IACf,CAAC;AAAA,EACH,SAAS,OAAY;AACnB,aAAS,KAAK;AACd,iBAAa,0BAA0B,EAAE,SAAS,MAAM,CAAC;AACzD,QAAI,MAAM,SAAS,qBAAqB;AACtC,MAAM,WAAI,MAAM,UAAU,QAAQ,MAAM,mBAAmB;AAC3D,cAAQ;AAAA,QACN;AAAA,MAASA,IAAG,KAAK,2BAA2B,QAAQ,MAAM,EAAE,CAAC;AAAA;AAAA,MAC/D;AACA,cAAQ,KAAK,CAAC;AACd;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;AAKA,eAAsB,aAAa,SAGjB;AAChB,EAAM,aAAMA,IAAG,KAAK,iBAAiB,QAAQ,MAAM,WAAW,CAAC;AAE/D,QAAM,WAAW,IAAI,mBAAmB;AACxC,QAAM,SAAS,MAAM,aAAa;AAClC,QAAM,YAAY,IAAIC,aAAY,EAAE,OAAO,CAAC;AAE5C,MAAI;AAEF,UAAM,SAAS,QAAQ,6BAA6B,YAAY;AAC9D,YAAM,UAAU;AAAA,QACd,IAAI,wBAAwB,EAAE,eAAe,QAAQ,OAAO,CAAC;AAAA,MAC/D;AAAA,IACF,CAAC;AAED,aAAS,KAAK;AAGd,QAAI,CAAC,QAAQ,OAAO;AAClB,YAAM,iBAAiB,MAAY,eAAQ;AAAA,QACzC,SAAS,mCAAmCD,IAAG,IAAI,QAAQ,MAAM,CAAC;AAAA,QAClE,cAAc;AAAA,MAChB,CAAC;AAED,UAAU,gBAAS,cAAc,KAAK,CAAC,gBAAgB;AACrD,QAAM,cAAO,qBAAqB;AAClC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAGA,UAAM,EAAE,2BAA2B,IAAI,MAAM,OAC3C,uBACF;AACA,UAAM,SAAS,QAAQ,4BAA4B,YAAY;AAC7D,YAAM,UAAU;AAAA,QACd,IAAI,2BAA2B;AAAA,UAC7B,eAAe,QAAQ;AAAA,QACzB,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,aAAS,KAAK;AACd,IAAM,aAAMA,IAAG,MAAM,iBAAY,QAAQ,MAAM,uBAAuB,CAAC;AAGvE,iBAAa,wBAAwB;AAAA,MACnC,SAAS;AAAA,IACX,CAAC;AACD,iBAAa,kBAAkB,CAAC,CAAC;AAAA,EACnC,SAAS,OAAY;AACnB,aAAS,KAAK;AACd,iBAAa,wBAAwB,EAAE,SAAS,MAAM,CAAC;AACvD,QAAI,MAAM,SAAS,qBAAqB;AACtC,MAAM,WAAI,MAAM,UAAU,QAAQ,MAAM,mBAAmB;AAC3D,cAAQ,KAAK,CAAC;AACd;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;;;ACpkBA;AAAA,YAAYE,YAAW;AACvB,YAAYC,aAAY;AACxB,OAAOC,SAAQ;AAEf;AAUA;AACA;AACA;AAIA;AAeA;AAeA,eAAsB,KAAK,SAAqC;AAC9D,QAAM,YAAY,KAAK,IAAI;AAE3B,EAAM;AAAA,IACJC,IAAG;AAAA,MACD,QAAQ,UACJ,uCACA;AAAA,IACN;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,mBAAmB;AAGxC,QAAM,mBAAmB,MAAM,SAAS;AAAA,IACtC;AAAA,IACA,YAAY,MAAM,sBAAsB;AAAA,EAC1C;AAEA,MAAI,kBAAkB;AACpB,aAAS,KAAK,wCAAwC;AAAA,EACxD;AAGA,QAAM,WAAW,MAAM,SAAS;AAAA,IAC9B;AAAA,IACA,YAAY,uBAAuB;AAAA,EACrC;AAEA,WAAS,KAAK,6BAA6BA,IAAG,KAAK,SAAS,SAAS,CAAC,EAAE;AAGxE,MAAI,WAAW,QAAQ;AACvB,MAAI,CAAC,UAAU;AACb,eAAW,MAAM,eAAe;AAAA,EAClC;AAEA,MAAI,SAAS,QAAQ;AACrB,MAAI,CAAC,QAAQ;AACX,UAAM,gBAAgB,MAAM,aAAa;AACzC,aAAS,MAAM,aAAa,aAAa;AAAA,EAC3C;AAEA,MAAI,SAAS,QAAQ;AACrB,MAAI,CAAC,QAAQ;AACX,aAAS,MAAM,aAAa;AAAA,EAC9B;AAGA,MAAI;AACJ,MAAI,aAAa,UAAU;AACzB,mBAAe,MAAM,mBAAmB;AAAA,EAC1C;AAGA,QAAM,qBAAqB,MAAM;AAAA,IAC/B,SAAS;AAAA,IACT;AAAA,EACF;AACA,MAAI,oBAAoB;AACtB,IAAM,WAAI;AAAA,MACR,yCAAyCA,IAAG,KAAK,SAAS,SAAS,CAAC,cAAcA,IAAG,KAAK,MAAM,CAAC;AAAA,IACnG;AACA,IAAM,WAAI,KAAK,YAAY,mBAAmB,SAAS,EAAE;AACzD,IAAM,WAAI,KAAK,OAAOA,IAAG,KAAK,cAAc,CAAC,wBAAwB;AACrE,IAAM,WAAI,KAAK,OAAOA,IAAG,KAAK,eAAe,CAAC,uBAAuB;AACrE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,MAAI,SAAS,QAAQ;AACrB,MAAI,CAAC,QAAQ;AACX,aAAS,MAAM,mBAAmB;AAAA,EACpC;AAEA,MAAI;AACJ,MAAI,WAAW,UAAU;AACvB,kBAAc,MAAM,mBAAmB;AAAA,EACzC,OAAO;AACL,kBAAc,UAAU,MAAM;AAG9B,UAAM,EAAE,sBAAAC,sBAAqB,IAAI,MAAM;AAGvC,UAAM,kBAAkB,MAAMA,sBAAqB;AACnD,gBAAY,iBAAiB;AAAA,EAC/B;AAGA,MAAI,QAAQ;AACV,gBAAY,SAAS;AAAA,EACvB;AAGA,QAAM,kBAAkB,MAAM,sBAAsB;AAGpD,WAAS,KAAK;AAAA,EAAKD,IAAG,KAAK,gBAAgB,CAAC,EAAE;AAC9C,QAAM,cAAc,eAAe,aAAa,eAAe;AAC/D,EAAM,WAAI,KAAK,WAAW;AAG1B,QAAM,WAAW,eAAe,WAAW;AAC3C,MAAI,SAAS,SAAS,GAAG;AACvB,aAAS,KAAK;AAAA,EAAKA,IAAG,OAAOA,IAAG,KAAK,yBAAyB,CAAC,CAAC,EAAE;AAClE,eAAW,WAAW,UAAU;AAC9B,MAAM,WAAI,KAAK,OAAO;AAAA,IACxB;AAAA,EACF;AAGA,QAAM,WAAW;AAAA,IACf,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,WAAW,SAAY;AAAA,EACpC;AACA,MAAI,cAAc;AAChB,aAAS,SAAS;AAAA,EACpB;AAGA,MAAI,EAAE,QAAQ,OAAO,QAAQ,UAAU;AACrC,UAAM,YAAY,MAAM,cAAc;AACtC,QAAI,CAAC,WAAW;AACd,MAAM,cAAO,uBAAuB;AACpC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAGA,QAAM,cAAgC;AAAA,IACpC;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,EACF;AAGA,MAAI,QAAQ,SAAS;AAEnB,QAAI;AACF,YAAM,gBAAgB,MAAM,SAAS;AAAA,QACnC;AAAA,QACA,YAAY;AACV,gBAAM,oBAAoB;AAE1B,gBAAM,QACJ,MAAa,mBAAW,eAAe;AAAA,YACrC;AAAA,cACE,WAAW,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,cAChD,aAAa;AAAA,cACb,SAAS,YAAY;AACnB,sBAAME,UAAS,MAAM,iBAAiB,WAAW;AACjD,uBAAO;AAAA,kBACL,SAASA,QAAO;AAAA,kBAChB,eAAeA,QAAO;AAAA,kBACtB,WAAWA,QAAO;AAAA,kBAClB,QAAQA,QAAO;AAAA,kBACf,iBAAiBA,QAAO;AAAA,kBACxB,QAAQA,QAAO;AAAA,kBACf,YAAYA,QAAO;AAAA,kBACnB,sBAAsBA,QAAO;AAAA,kBAC7B,gBAAgBA,QAAO;AAAA,kBACvB,YAAYA,QAAO;AAAA,kBACnB,kBAAkBA,QAAO;AAAA,kBACzB,kBAAkBA,QAAO;AAAA,gBAC3B;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,SAAS,iBAAiB;AAAA,cAC1B,SAAS;AAAA,gBACP,0BAA0B;AAAA,gBAC1B,YAAY;AAAA,cACd;AAAA,cACA,iBAAiB;AAAA,YACnB;AAAA,UACF;AAEF,gBAAM,MAAM,UAAU,cAAc,EAAE,OAAO,OAAO,CAAC;AAGrD,gBAAM,SAAS,MAAM,MAAM,QAAQ,EAAE,MAAM,KAAK,CAAC;AACjD,iBAAO;AAAA,QACT;AAAA,MACF;AAGA,qBAAe;AAAA,QACb,eAAe,cAAc;AAAA,QAC7B,cAAc;AAAA,QACd,aAAa;AAAA,MACf,CAAC;AAED,MAAM;AAAA,QACJF,IAAG,MAAM,oDAAoD;AAAA,MAC/D;AAGA,uBAAiB,SAAS,MAAM;AAAA,QAC9B;AAAA,QACA;AAAA,QACA,SAAS;AAAA,QACT,aAAa,KAAK,IAAI,IAAI;AAAA,MAC5B,CAAC;AACD;AAAA,IACF,SAAS,OAAY;AACnB,iBAAW,kBAAkB,cAAc,EAAE,MAAM,UAAU,CAAC;AAC9D,UAAI,MAAM,SAAS,SAAS,2BAA2B,GAAG;AACxD,cAAM,OAAO,YAAY;AAAA,MAC3B;AACA,YAAM,IAAI,MAAM,mBAAmB,MAAM,OAAO,EAAE;AAAA,IACpD;AAAA,EACF;AAGA,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,SAAS;AAAA,MACvB;AAAA,MACA,YAAY;AAEV,cAAM,oBAAoB;AAG1B,cAAM,QACJ,MAAa,mBAAW,eAAe;AAAA,UACrC;AAAA,YACE,WAAW,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,YAChD,aAAa;AAAA,YACb,SAAS,YAAY;AACnB,oBAAM,SAAS,MAAM,iBAAiB,WAAW;AAGjD,qBAAO;AAAA,gBACL,SAAS,OAAO;AAAA,gBAChB,eAAe,OAAO;AAAA,gBACtB,WAAW,OAAO;AAAA,gBAClB,QAAQ,OAAO;AAAA,gBACf,iBAAiB,OAAO;AAAA,gBACxB,QAAQ,OAAO;AAAA,gBACf,YAAY,OAAO;AAAA,gBACnB,sBAAsB,OAAO;AAAA,gBAC7B,gBAAgB,OAAO;AAAA,gBACvB,YAAY,OAAO;AAAA,gBACnB,kBAAkB,OAAO;AAAA,gBACzB,kBAAkB,OAAO;AAAA,cAC3B;AAAA,YACF;AAAA,UACF;AAAA,UACA;AAAA,YACE,SAAS,iBAAiB;AAAA;AAAA,YAE1B,SAAS;AAAA,cACP,0BAA0B;AAAA;AAAA,cAC1B,YAAY;AAAA,YACd;AAAA,YACA,iBAAiB;AAAA,UACnB;AAAA,QACF;AAGF,cAAM,MAAM,UAAU;AAAA,UACpB,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,QACvC;AAGA,cAAM,MAAM,UAAU,cAAc,EAAE,OAAO,OAAO,CAAC;AAGrD,cAAM,WAAW,MAAM,MAAM,GAAG,EAAE,UAAU,MAAM;AAAA,QAAC,EAAE,CAAC;AAGtD,cAAM,gBAAgB,SAAS;AAE/B,eAAO;AAAA,UACL,SAAS,cAAc,SAAS;AAAA,UAChC,eAAe,cAAc,eAAe;AAAA,UAG5C,WAAW,cAAc,WAAW;AAAA,UACpC,QAAQ,cAAc,QAAQ;AAAA,UAC9B,iBAAiB,cAAc,iBAAiB;AAAA,UAGhD,QAAQ,cAAc,QAAQ;AAAA,UAC9B,YAAY,cAAc,YAAY;AAAA,UACtC,sBAAsB,cAAc,sBAAsB;AAAA,UAG1D,gBAAgB,cAAc,gBAAgB;AAAA,UAG9C,YAAY,cAAc,YAAY;AAAA,UACtC,kBAAkB,cAAc,kBAAkB;AAAA,UAGlD,kBAAkB,cAAc,kBAAkB;AAAA,QAGpD;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAY;AAEnB,qBAAiB,SAAS,OAAO;AAAA,MAC/B;AAAA,MACA;AAAA,MACA,aAAa,KAAK,IAAI,IAAI;AAAA,IAC5B,CAAC;AAGD,QAAI,MAAM,SAAS,SAAS,2BAA2B,GAAG;AACxD,iBAAW,gBAAgB,cAAc,EAAE,MAAM,SAAS,CAAC;AAC3D,YAAM,OAAO,YAAY;AAAA,IAC3B;AAEA,eAAW,qBAAqB,cAAc,EAAE,MAAM,SAAS,CAAC;AAChE,UAAM,IAAI,MAAM,6BAA6B,MAAM,OAAO,EAAE;AAAA,EAC9D;AAGA,MAAI,SAAS,SAAS,OAAO;AAC3B,aAAS,SAAS,MAAM,kBAAkB,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,EACjF;AACA,QAAM,uBAAuB,QAAQ;AAErC,WAAS,KAAK,8DAA8D;AAG5E,MAAI,iBAAiB;AACrB,MAAI,QAAQ,UAAU,QAAQ,cAAc,QAAQ,WAAW,SAAS,GAAG;AACzE,UAAM,EAAE,gBAAAG,iBAAgB,kBAAAC,kBAAiB,IAAI,MAAM;AAGnD,UAAM,aAAa,MAAMD,gBAAe,QAAQ,QAAQ,MAAM;AAE9D,QAAI,YAAY;AACd,UAAI;AACF,iBAAS,MAAM,iCAAiC;AAChD,cAAMC;AAAA,UACJ,WAAW;AAAA,UACX,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ;AAAA,UACR,QAAQ;AAAA,QACV;AACA,iBAAS,QAAQ,gCAAgC;AACjD,yBAAiB;AAAA,MACnB,SAAS,OAAY;AACnB,iBAAS,KAAK,yCAAyC;AACvD,QAAM,WAAI,KAAK,sCAAsC,MAAM,OAAO,EAAE;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAGA,QAAM,aAAa,CAAC;AACpB,MACE,QAAQ,UACR,QAAQ,cACR,QAAQ,WAAW,SAAS,KAC5B,CAAC,gBACD;AAEA,eAAW,SAAS,QAAQ,YAAY;AACtC,iBAAW,KAAK;AAAA,QACd,MAAM,GAAG,KAAK,eAAe,QAAQ,MAAM;AAAA,QAC3C,MAAM;AAAA,QACN,OAAO,GAAG,KAAK;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AAGA,iBAAe;AAAA,IACb,SAAS,QAAQ;AAAA,IACjB,eAAe,QAAQ;AAAA,IACvB,QAAQ,QAAQ;AAAA,IAChB,WAAW,QAAQ;AAAA,IACnB,YAAY,WAAW,SAAS,IAAI,aAAa;AAAA,IACjD;AAAA,IACA,QAAQ,QAAQ;AAAA,IAChB,gBAAgB,QAAQ;AAAA,EAC1B,CAAC;AAGD,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,QAAM,kBAA4B,CAAC;AACnC,MAAI,YAAY,UAAU,QAAS,iBAAgB,KAAK,UAAU;AAClE,MAAI,YAAY,iBAAiB;AAC/B,oBAAgB,KAAK,kBAAkB;AACzC,MAAI,YAAY,eAAe;AAC7B,oBAAgB,KAAK,gBAAgB;AACvC,MAAI,YAAY,eAAe;AAC7B,oBAAgB,KAAK,kBAAkB;AACzC,MAAI,YAAY,YAAa,iBAAgB,KAAK,cAAc;AAChE,MAAI,YAAY,gBAAgB;AAC9B,oBAAgB,KAAK,iBAAiB;AAExC,mBAAiB,SAAS,MAAM;AAAA,IAC9B;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,aAAa;AAAA,EACf,CAAC;AAED,uBAAqB,SAAS;AAAA,IAC5B,aAAa;AAAA,IACb,UAAU;AAAA,IACV;AAAA,EACF,CAAC;AACH;;;ACldA;AAGA;AAKA;AARA,YAAYC,YAAW;AACvB,YAAYC,aAAY;AACxB,OAAOC,UAAQ;AA2Bf,eAAsB,QAAQ,SAA6C;AACzE,QAAM,YAAY,KAAK,IAAI;AAE3B,EAAM;AAAA,IACJC,KAAG;AAAA,MACD,QAAQ,UACJ,0BACA;AAAA,IACN;AAAA,EACF;AAEA,EAAM,WAAI;AAAA,IACR,GAAGA,KAAG,OAAO,OAAO,CAAC;AAAA,EACvB;AACA,EAAM,WAAI;AAAA,IACR;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,mBAAmB;AAGxC,QAAM,WAAW,MAAM,SAAS;AAAA,IAC9B;AAAA,IACA,YAAY,uBAAuB;AAAA,EACrC;AAEA,WAAS,KAAK,6BAA6BA,KAAG,KAAK,SAAS,SAAS,CAAC,EAAE;AAGxE,MAAI,SAAS,QAAQ;AACrB,MAAI,CAAC,QAAQ;AACX,UAAM,gBAAgB,MAAM,aAAa;AACzC,aAAS;AAAA,EACX;AAGA,QAAM,WAAW,MAAM,uBAAuB,SAAS,WAAW,MAAM;AAExE,MAAI,CAAC,UAAU;AACb,IAAM,WAAI;AAAA,MACR,yCAAyCA,KAAG,KAAK,SAAS,SAAS,CAAC,cAAcA,KAAG,KAAK,MAAM,CAAC;AAAA,IACnG;AACA,IAAM,WAAI;AAAA,MACR,OAAOA,KAAG,KAAK,kBAAkB,CAAC,OAAOA,KAAG,KAAK,qBAAqB,CAAC;AAAA,IACzE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,WAAS,KAAK,6BAA6B,SAAS,SAAS,EAAE;AAG/D,UAAQ;AAAA,IACN;AAAA,EAAKA,KAAG,KAAK,gDAAgD,CAAC;AAAA;AAAA,EAChE;AAEA,MAAI,SAAS,SAAS,OAAO,OAAO,UAAU,SAAS;AACrD,YAAQ,IAAI,KAAKA,KAAG,KAAK,QAAG,CAAC,2CAA2C;AAAA,EAC1E;AACA,MAAI,SAAS,SAAS,OAAO,OAAO,eAAe,iBAAiB;AAClE,YAAQ,IAAI,KAAKA,KAAG,KAAK,QAAG,CAAC,uCAAuC;AAAA,EACtE;AACA,MAAI,SAAS,SAAS,OAAO,OAAO,eAAe,SAAS;AAC1D,YAAQ,IAAI,KAAKA,KAAG,KAAK,QAAG,CAAC,oBAAoB;AACjD,YAAQ,IAAI,KAAKA,KAAG,KAAK,QAAG,CAAC,aAAa;AAC1C,YAAQ,IAAI,KAAKA,KAAG,KAAK,QAAG,CAAC,mBAAmB;AAAA,EAClD;AACA,UAAQ,IAAI,KAAKA,KAAG,KAAK,QAAG,CAAC,8BAA8B;AAC3D,UAAQ,IAAI,EAAE;AAGd,MAAI,EAAE,QAAQ,SAAS,QAAQ,UAAU;AACvC,UAAM,YAAY,MAAY,eAAQ;AAAA,MACpC,SAAS;AAAA,MACT,cAAc;AAAA,IAChB,CAAC;AAED,QAAU,gBAAS,SAAS,KAAK,CAAC,WAAW;AAC3C,MAAM,cAAO,oBAAoB;AACjC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAGA,MAAI,QAAQ,SAAS;AAEnB,QAAI,SAAS,SAAS,OAAO,iBAAiB;AAC5C,UAAI;AACF,cAAM,gBAAgB,MAAM,SAAS;AAAA,UACnC;AAAA,UACA,YAAY;AACV,kBAAM,QAAQ,MAAa,mBAAW,eAAe;AAAA,cACnD;AAAA,gBACE,WAAW,SAAS,SAAS,MAAO;AAAA,gBACpC,aAAa;AAAA,gBACb,SAAS,YAAY;AAAA,gBAAC;AAAA;AAAA,cACxB;AAAA,cACA;AAAA,gBACE,SAAS,iBAAiB;AAAA,gBAC1B,SAAS;AAAA,kBACP,0BAA0B;AAAA,kBAC1B,YAAY;AAAA,gBACd;AAAA,gBACA,iBAAiB;AAAA,cACnB;AAAA,YACF;AAGA,kBAAM,SAAS,MAAM,MAAM,QAAQ,EAAE,MAAM,KAAK,CAAC;AACjD,mBAAO;AAAA,UACT;AAAA,QACF;AAGA,uBAAe;AAAA,UACb,eAAe,cAAc;AAAA,UAC7B,cAAc;AAAA,UACd,aAAa;AAAA,QACf,CAAC;AAED,QAAM;AAAA,UACJA,KAAG;AAAA,YACD;AAAA,UACF;AAAA,QACF;AAGA,4BAAoB,SAAS;AAAA,UAC3B,SAAS;AAAA,UACT,aAAa,KAAK,IAAI,IAAI;AAAA,QAC5B,CAAC;AACD;AAAA,MACF,SAAS,OAAY;AACnB,mBAAW,kBAAkB,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACjE,cAAM,IAAI,MAAM,mBAAmB,MAAM,OAAO,EAAE;AAAA,MACpD;AAAA,IACF;AACA;AAAA,EACF;AAGA,MAAI,SAAS,SAAS,OAAO,iBAAiB;AAC5C,UAAM,SAAS,QAAQ,iCAAiC,YAAY;AAClE,UAAI;AACF,YAAI,CAAC,SAAS,SAAS,OAAO,iBAAiB;AAC7C,gBAAM,IAAI,MAAM,wCAAwC;AAAA,QAC1D;AAEA,cAAM,QAAQ,MAAa,mBAAW,eAAe;AAAA,UACnD;AAAA,YACE,WAAW,SAAS,SAAS,MAAM;AAAA,YACnC,aAAa;AAAA,YACb,SAAS,YAAY;AAAA,YAAC;AAAA;AAAA,UACxB;AAAA,UACA;AAAA,YACE,SAAS,iBAAiB;AAAA,YAC1B,SAAS;AAAA,cACP,0BAA0B;AAAA,cAC1B,YAAY;AAAA,YACd;AAAA,YACA,iBAAiB;AAAA,UACnB;AAAA,QACF;AAGA,cAAM,MAAM,QAAQ,EAAE,UAAU,MAAM;AAAA,QAAC,EAAE,CAAC;AAG1C,cAAM,MAAM,UAAU;AAAA,UACpB,SAAS,SAAS,MAAM;AAAA,QAC1B;AAAA,MACF,SAAS,OAAY;AACnB,mBAAW,kBAAkB,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACjE,cAAM,IAAI,MAAM,mCAAmC,MAAM,OAAO,EAAE;AAAA,MACpE;AAAA,IACF,CAAC;AAAA,EACH;AAGA,QAAM,yBAAyB,SAAS,WAAW,MAAM;AAEzD,WAAS,KAAK,6BAA6B;AAG3C,UAAQ;AAAA,IACN;AAAA,EAAKA,KAAG,MAAM,QAAG,CAAC,IAAIA,KAAG,KAAK,sCAAsC,CAAC;AAAA;AAAA,EACvE;AACA,UAAQ;AAAA,IACN,GAAGA,KAAG,IAAI,8DAA8D,CAAC;AAAA,EAC3E;AACA,UAAQ,IAAI,GAAGA,KAAG,IAAI,+CAA+C,CAAC;AAAA,CAAI;AAG1E,sBAAoB,SAAS;AAAA,IAC3B,QAAQ;AAAA,IACR,aAAa,KAAK,IAAI,IAAI;AAAA,EAC5B,CAAC;AACH;;;ACjOA;AAGA;AAEA;AALA,YAAYC,aAAW;AACvB,YAAYC,cAAY;AACxB,OAAOC,UAAQ;AAoBf,eAAsB,YAAY,UAAwC;AACxE,QAAM,YAAY,KAAK,IAAI;AAC3B,QAAM,WAAW,IAAI,mBAAmB;AAExC,EAAM,cAAMC,KAAG,KAAK,oBAAoB,CAAC;AAGzC,QAAM,WAAW,MAAM,SAAS;AAAA,IAC9B;AAAA,IACA,YAAY,uBAAuB;AAAA,EACrC;AAGA,QAAM,SAAS,MAAM,aAAa;AAGlC,MAAI,eAAoB,CAAC;AACzB,MAAI;AAEF,UAAM,oBAAoB;AAE1B,UAAM,QAAQ,MAAa,oBAAW,eAAe,YAAY;AAAA,MAC/D,WAAW,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,MAChD,SAAS,iBAAiB;AAAA,IAC5B,CAAC;AAED,mBAAe,MAAM,MAAM,QAAQ;AAAA,EACrC,SAAS,QAAa;AACpB,aAAS,KAAK;AACd,IAAM,YAAI,MAAM,+BAA+B;AAC/C,YAAQ;AAAA,MACN;AAAA,MAASA,KAAG,KAAK,kBAAkB,CAAC;AAAA;AAAA,IACtC;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,UAAU,MAAM,eAAe,MAAM;AAG3C,QAAM,EAAE,aAAAC,cAAa,yBAAAC,yBAAwB,IAAI,MAAM,OACrD,uBACF;AACA,QAAM,cAAc,IAAID,aAAY,EAAE,OAAO,CAAC;AAE9C,QAAM,oBAAoB,MAAM,QAAQ;AAAA,IACtC,QAAQ,IAAI,OAAO,MAAM;AACvB,UAAI;AACF,cAAME,YAAW,MAAM,YAAY;AAAA,UACjC,IAAID,yBAAwB,EAAE,eAAe,EAAE,OAAO,CAAC;AAAA,QACzD;AACA,eAAO;AAAA,UACL,QAAQ,EAAE;AAAA,UACV,QAAQ,EAAE,WAAY,aAAwB;AAAA,UAC9C,YAAYC,UAAS,gBAAgB,UAAU,CAAC;AAAA,UAChD,gBAAgBA,UAAS,oBAAoB;AAAA,UAC7C,gBAAgBA,UAAS,oBAAoB;AAAA,QAC/C;AAAA,MACF,SAAS,QAAQ;AACf,eAAO;AAAA,UACL,QAAQ,EAAE;AAAA,UACV,QAAQ,EAAE,WAAY,aAAwB;AAAA,UAC9C,YAAY;AAAA,UACZ,gBAAgB;AAAA,UAChB,gBAAgB;AAAA,QAClB;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAGA,QAAM,mBAAmB,aAAa,gBAClC,aACA;AAGJ,WAAS,KAAK;AACd,gBAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,WAAW;AAAA,MACT,SAAS,aAAa,SAAS;AAAA,MAC/B,eAAe,aAAa,eAAe;AAAA,MAC3C,WAAW,aAAa,WAAW;AAAA,MACnC,iBAAiB,aAAa,iBAAiB,OAAO,UAAU;AAAA,MAChE,WAAW,qBAAqB,aAAa,IAAI;AAAA,MACjD,YAAY,aAAa,YAAY;AAAA,MACrC,kBAAkB,aAAa,kBAAkB;AAAA,MACjD,kBAAkB,aAAa,kBAAkB;AAAA,IACnD;AAAA,IACA,UAAU,aAAa,sBAAsB,QACzC;AAAA,MACE,sBAAsB,aAAa,sBAAsB;AAAA,MACzD,cAAc,aAAa,sBAAsB;AAAA,MACjD,kBAAkB,aAAa,kBAAkB;AAAA,IACnD,IACA;AAAA,EACN,CAAC;AAGD,eAAa,gBAAgB;AAAA,IAC3B,SAAS;AAAA,IACT,cAAc,kBAAkB;AAAA,IAChC,mBAAmB;AAAA,IACnB,aAAa,KAAK,IAAI,IAAI;AAAA,EAC5B,CAAC;AACH;;;ACjIA;AAAA,YAAYC,aAAW;AACvB,YAAYC,cAAY;AACxB,OAAOC,UAAQ;AAEf;AASA;AACA;AACA;AAIA;AAgBA;AAMA,eAAsB,QAAQ,SAAwC;AACpE,QAAM,YAAY,KAAK,IAAI;AAC3B,MAAI,gBAAiC;AAErC,EAAM;AAAA,IACJC,KAAG;AAAA,MACD,QAAQ,UACJ,0BACA;AAAA,IACN;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,mBAAmB;AAGxC,QAAM,mBAAmB,MAAM,SAAS;AAAA,IACtC;AAAA,IACA,YAAY,MAAM,sBAAsB;AAAA,EAC1C;AAEA,MAAI,kBAAkB;AACpB,aAAS,KAAK,wCAAwC;AAAA,EACxD;AAGA,QAAM,WAAW,MAAM,SAAS;AAAA,IAC9B;AAAA,IACA,YAAY,uBAAuB;AAAA,EACrC;AAEA,WAAS,KAAK,6BAA6BA,KAAG,KAAK,SAAS,SAAS,CAAC,EAAE;AAGxE,MAAI,SAAS,QAAQ;AACrB,MAAI,CAAC,QAAQ;AACX,UAAM,gBAAgB,MAAM,aAAa;AACzC,aAAS;AAAA,EACX;AAGA,QAAM,WAAW,MAAM,uBAAuB,SAAS,WAAW,MAAM;AAExE,MAAI,CAAC,UAAU;AACb,IAAM,YAAI;AAAA,MACR,yCAAyCA,KAAG,KAAK,SAAS,SAAS,CAAC,cAAcA,KAAG,KAAK,MAAM,CAAC;AAAA,IACnG;AACA,IAAM,YAAI;AAAA,MACR,OAAOA,KAAG,KAAK,kBAAkB,CAAC,oCAAoCA,KAAG,KAAK,qBAAqB,CAAC;AAAA,IACtG;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,WAAS,KAAK,sCAAsC,SAAS,SAAS,EAAE;AAGxE,UAAQ,IAAI;AAAA,EAAKA,KAAG,KAAK,wBAAwB,CAAC;AAAA,CAAI;AAEtD,MAAI,SAAS,SAAS,OAAO,QAAQ;AACnC,YAAQ,IAAI,aAAaA,KAAG,KAAK,SAAS,SAAS,OAAO,MAAM,CAAC,EAAE;AAAA,EACrE,OAAO;AACL,YAAQ,IAAI,aAAaA,KAAG,KAAK,QAAQ,CAAC,EAAE;AAAA,EAC9C;AAEA,QAAMC,UAAS,SAAS,SAAS,OAAO;AAExC,MAAI,CAACA,SAAQ;AACX,IAAM,YAAI,MAAM,0CAA0C;AAC1D,IAAM,YAAI;AAAA,MACR,OAAOD,KAAG,KAAK,kBAAkB,CAAC;AAAA,IACpC;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,MAAIC,QAAO,QAAQ;AACjB,YAAQ,IAAI,qBAAqBD,KAAG,KAAKC,QAAO,MAAM,CAAC,EAAE;AAAA,EAC3D;AAEA,MAAIA,QAAO,UAAU,SAAS;AAC5B,YAAQ,IAAI,KAAKD,KAAG,MAAM,QAAG,CAAC,wBAAwB;AACtD,QAAIC,QAAO,SAAS,sBAAsB;AACxC,cAAQ;AAAA,QACN,OAAOD,KAAG,IAAI,cAAI,CAAC,mBAAmBA,KAAG,KAAKC,QAAO,SAAS,oBAAoB,CAAC;AAAA,MACrF;AAAA,IACF;AAAA,EACF;AAEA,MAAIA,QAAO,iBAAiB,SAAS;AACnC,YAAQ,IAAI,KAAKD,KAAG,MAAM,QAAG,CAAC,+BAA+B;AAAA,EAC/D;AAEA,MAAIC,QAAO,eAAe,SAAS;AACjC,YAAQ,IAAI,KAAKD,KAAG,MAAM,QAAG,CAAC,+BAA+B;AAC7D,QAAIC,QAAO,cAAc,iBAAiB;AACxC,cAAQ;AAAA,QACN,OAAOD,KAAG,IAAI,cAAI,CAAC,mBAAmBA,KAAG,KAAKC,QAAO,cAAc,oBAAoB,QAAQ,CAAC;AAAA,MAClG;AAAA,IACF;AAAA,EACF;AAEA,MAAIA,QAAO,aAAa;AACtB,YAAQ,IAAI,KAAKD,KAAG,MAAM,QAAG,CAAC,uBAAuB;AAAA,EACvD;AAEA,MAAIC,QAAO,gBAAgB,SAAS;AAClC,UAAM,iBACJ;AAAA,MACE,SAAS;AAAA,MACT,UAAU;AAAA,MACV,UAAU;AAAA,MACV,WAAW;AAAA,MACX,WAAW;AAAA,MACX,WAAW;AAAA,MACX,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,WAAW;AAAA,IACb,EAAEA,QAAO,eAAe,SAAS,KAAK;AACxC,YAAQ,IAAI,KAAKD,KAAG,MAAM,QAAG,CAAC,qBAAqB,cAAc,GAAG;AAAA,EACtE;AAGA,QAAM,kBAAkB,eAAeC,SAAQ,GAAM;AACrD,UAAQ;AAAA,IACN;AAAA,oBAAuBD,KAAG,KAAK,IAAI,WAAW,gBAAgB,MAAM,OAAO,CAAC,KAAK,CAAC;AAAA,EACpF;AAEA,UAAQ,IAAI,EAAE;AAGd,kBAAgB,MAAY,eAAO;AAAA,IACjC,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAOC,QAAO,gBAAgB,UAC1B,oCACA;AAAA,QACJ,MAAMA,QAAO,gBAAgB,UACzB,gCACA;AAAA,MACN;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAU,iBAAS,aAAa,GAAG;AACjC,IAAM,eAAO,oBAAoB;AACjC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,gBAAkC,EAAE,GAAGA,QAAO;AAClD,MAAI,YAAgC,SAAS,SAAS,OAAO;AAG7D,UAAQ,eAAe;AAAA,IACrB,KAAK,UAAU;AAEb,YAAM,UAAU,iBAAiB;AACjC,YAAM,mBAAmB,QAAQ;AAAA,QAC/B,CAAC,MAAM,EAAE,KAAK,YAAY,MAAM,SAAS,SAAS,OAAO;AAAA,MAC3D;AAEA,YAAM,mBAAmB,QACtB,IAAI,CAAC,GAAG,SAAS;AAAA,QAChB,OAAO,EAAE,KAAK,YAAY;AAAA,QAC1B,OAAO,GAAG,EAAE,IAAI,MAAM,EAAE,WAAW;AAAA,QACnC,MAAM,GAAG,EAAE,MAAM,WAAW,EAAE,aAAa;AAAA,QAC3C,UACE,oBAAoB,KAAK,OAAO,mBAC5B,0BACA;AAAA,MACR,EAAE,EACD,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ;AAE5B,UAAI,iBAAiB,WAAW,GAAG;AACjC,QAAM,YAAI,KAAK,wCAAwC;AACvD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,iBAAiB,MAAY,eAAO;AAAA,QACxC,SAAS;AAAA,QACT,SAAS;AAAA,MACX,CAAC;AAED,UAAU,iBAAS,cAAc,GAAG;AAClC,QAAM,eAAO,oBAAoB;AACjC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAGA,YAAM,eAAe,UAAU,cAAqB;AAGpD,sBAAgB,mBAAmBA,SAAQ,YAAY;AACvD,kBAAY;AACZ;AAAA,IACF;AAAA,IAEA,KAAK,aAAa;AAChB,UAAIA,QAAO,gBAAgB,SAAS;AAElC,cAAM,kBAAkB,MAAY,eAAO;AAAA,UACzC,SAAS;AAAA,UACT,SAAS;AAAA,YACP;AAAA,cACE,OAAO;AAAA,cACP,OAAO;AAAA,cACP,MAAM,YAAYA,QAAO,eAAe,SAAS;AAAA,YACnD;AAAA,YACA;AAAA,cACE,OAAO;AAAA,cACP,OAAO;AAAA,cACP,MAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF,CAAC;AAED,YAAU,iBAAS,eAAe,GAAG;AACnC,UAAM,eAAO,oBAAoB;AACjC,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAEA,YAAI,oBAAoB,WAAW;AACjC,gBAAM,iBAAiB,MAAY,gBAAQ;AAAA,YACzC,SACE;AAAA,YACF,cAAc;AAAA,UAChB,CAAC;AAED,cAAU,iBAAS,cAAc,KAAK,CAAC,gBAAgB;AACrD,YAAM,eAAO,yBAAyB;AACtC,oBAAQ,KAAK,CAAC;AAAA,UAChB;AAEA,0BAAgB;AAAA,YACd,GAAGA;AAAA,YACH,gBAAgB;AAAA,cACd,SAAS;AAAA,cACT,WAAWA,QAAO,eAAe;AAAA,YACnC;AAAA,UACF;AAAA,QACF,OAAO;AAEL,gBAAM,YAAY,MAAY,eAAO;AAAA,YACnC,SAAS;AAAA,YACT,SAAS;AAAA,cACP;AAAA,gBACE,OAAO;AAAA,gBACP,OAAO;AAAA,gBACP,MAAM;AAAA,cACR;AAAA,cACA;AAAA,gBACE,OAAO;AAAA,gBACP,OAAO;AAAA,gBACP,MAAM;AAAA,cACR;AAAA,cACA;AAAA,gBACE,OAAO;AAAA,gBACP,OAAO;AAAA,gBACP,MAAM;AAAA,cACR;AAAA,cACA;AAAA,gBACE,OAAO;AAAA,gBACP,OAAO;AAAA,gBACP,MAAM;AAAA,cACR;AAAA,cACA;AAAA,gBACE,OAAO;AAAA,gBACP,OAAO;AAAA,gBACP,MAAM;AAAA,cACR;AAAA,cACA;AAAA,gBACE,OAAO;AAAA,gBACP,OAAO;AAAA,gBACP,MAAM;AAAA,cACR;AAAA,YACF;AAAA,YACA,cAAcA,QAAO,eAAe;AAAA,UACtC,CAAC;AAED,cAAU,iBAAS,SAAS,GAAG;AAC7B,YAAM,eAAO,oBAAoB;AACjC,oBAAQ,KAAK,CAAC;AAAA,UAChB;AAEA,0BAAgB;AAAA,YACd,GAAGA;AAAA,YACH,gBAAgB;AAAA,cACd,SAAS;AAAA,cACT;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,OAAO;AAEL,cAAM,kBAAkB,MAAY,gBAAQ;AAAA,UAC1C,SACE;AAAA,UACF,cAAc;AAAA,QAChB,CAAC;AAED,YAAU,iBAAS,eAAe,GAAG;AACnC,UAAM,eAAO,oBAAoB;AACjC,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAEA,YAAI,CAAC,iBAAiB;AACpB,UAAM,YAAI,KAAK,8BAA8B;AAC7C,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAEA,cAAM,YAAY,MAAY,eAAO;AAAA,UACnC,SAAS;AAAA,UACT,SAAS;AAAA,YACP;AAAA,cACE,OAAO;AAAA,cACP,OAAO;AAAA,cACP,MAAM;AAAA,YACR;AAAA,YACA;AAAA,cACE,OAAO;AAAA,cACP,OAAO;AAAA,cACP,MAAM;AAAA,YACR;AAAA,YACA;AAAA,cACE,OAAO;AAAA,cACP,OAAO;AAAA,cACP,MAAM;AAAA,YACR;AAAA,YACA;AAAA,cACE,OAAO;AAAA,cACP,OAAO;AAAA,cACP,MAAM;AAAA,YACR;AAAA,YACA;AAAA,cACE,OAAO;AAAA,cACP,OAAO;AAAA,cACP,MAAM;AAAA,YACR;AAAA,YACA;AAAA,cACE,OAAO;AAAA,cACP,OAAO;AAAA,cACP,MAAM;AAAA,YACR;AAAA,UACF;AAAA,UACA,cAAc;AAAA,QAChB,CAAC;AAED,YAAU,iBAAS,SAAS,GAAG;AAC7B,UAAM,eAAO,oBAAoB;AACjC,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAEA,QAAM,YAAI;AAAA,UACRD,KAAG;AAAA,YACD;AAAA,UACF;AAAA,QACF;AACA,QAAM,YAAI;AAAA,UACRA,KAAG;AAAA,YACD;AAAA,UACF;AAAA,QACF;AAEA,wBAAgB;AAAA,UACd,GAAGC;AAAA,UACH,gBAAgB;AAAA,YACd,SAAS;AAAA,YACT;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,kBAAY;AACZ;AAAA,IACF;AAAA,IAEA,KAAK,mBAAmB;AAEtB,UAAI,CAACA,QAAO,QAAQ;AAClB,QAAM,YAAI;AAAA,UACR;AAAA,QACF;AACA,QAAM,YAAI;AAAA,UACR,OAAOD,KAAG,KAAK,kBAAkB,CAAC;AAAA,QACpC;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAGA,YAAM,EAAE,gBAAAE,gBAAe,IAAI,MAAM;AACjC,YAAM,UAAU,MAAM,SAAS;AAAA,QAC7B;AAAA,QACA,YAAY,MAAMA,gBAAe,MAAM;AAAA,MACzC;AAEA,YAAM,gBAAgB,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAWD,QAAO,MAAM;AAEpE,UAAI,CAAC,eAAe,UAAU;AAC5B,QAAM,YAAI;AAAA,UACR,kBAAkBD,KAAG,KAAKC,QAAO,MAAM,CAAC;AAAA,QAC1C;AACA,QAAM,YAAI;AAAA,UACR;AAAA,QACF;AACA,QAAM,YAAI;AAAA,UACR,OAAOD,KAAG,KAAK,oBAAoB,CAAC;AAAA,QACtC;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,eAAS;AAAA,QACP,kBAAkBA,KAAG,KAAKC,QAAO,MAAM,CAAC,gBAAgBD,KAAG,MAAM,QAAG,CAAC;AAAA,MACvE;AAEA,YAAM,iBAAiB,MAAY,aAAK;AAAA,QACtC,SAAS;AAAA,QACT,aAAa;AAAA,QACb,cAAcC,QAAO,UAAU,wBAAwB;AAAA,QACvD,UAAU,CAAC,UAAU;AACnB,cAAI,SAAS,CAAC,2BAA2B,KAAK,KAAK,GAAG;AACpD,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF,CAAC;AAED,UAAU,iBAAS,cAAc,GAAG;AAClC,QAAM,eAAO,oBAAoB;AACjC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAGA,YAAM,cAAc,MAAY,gBAAQ;AAAA,QACtC,SAAS;AAAA,QACT,cAAc;AAAA,MAChB,CAAC;AAED,UAAU,iBAAS,WAAW,GAAG;AAC/B,QAAM,eAAO,oBAAoB;AACjC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,UAAI,aAAa;AACf,QAAM,YAAI;AAAA,UACRD,KAAG;AAAA,YACD;AAAA,UACF;AAAA,QACF;AACA,QAAM,YAAI;AAAA,UACRA,KAAG;AAAA,YACD;AAAA,UACF;AAAA,QACF;AAGA,cAAM,EAAE,gBAAAG,gBAAe,IAAI,MAAM;AACjC,cAAM,aAAa,MAAM,SAAS;AAAA,UAChC;AAAA,UACA,YACE,MAAMA,gBAAe,kBAAkBF,QAAO,QAAS,MAAM;AAAA,QACjE;AAEA,YAAI,YAAY;AACd,mBAAS;AAAA,YACP,8BAA8BD,KAAG,KAAK,WAAW,IAAI,CAAC,IAAIA,KAAG,MAAM,QAAG,CAAC;AAAA,UACzE;AACA,UAAM,YAAI;AAAA,YACRA,KAAG;AAAA,cACD;AAAA,YACF;AAAA,UACF;AAAA,QACF,OAAO;AACL,UAAM,YAAI;AAAA,YACR,oCAAoCA,KAAG,KAAK,kBAAkBC,QAAO,MAAO,CAAC;AAAA,UAC/E;AACA,UAAM,YAAI;AAAA,YACRD,KAAG;AAAA,cACD;AAAA,YACF;AAAA,UACF;AACA,UAAM,YAAI;AAAA,YACRA,KAAG,IAAI,oDAAoD;AAAA,UAC7D;AAAA,QACF;AAEA,cAAM,eAAe,MAAY,gBAAQ;AAAA,UACvC,SAAS,aACL,wCACA;AAAA,UACJ,cAAc;AAAA,QAChB,CAAC;AAED,YAAU,iBAAS,YAAY,KAAK,CAAC,cAAc;AACjD,UAAM,YAAI,KAAK,kDAAkD;AACjE,0BAAgB;AAAA,YACd,GAAGC;AAAA,YACH,UAAU;AAAA,cACR,GAAGA,QAAO;AAAA,cACV,SAAS;AAAA,cACT,sBAAsB,kBAAkB;AAAA,cACxC,cAAc;AAAA,YAChB;AAAA,UACF;AAAA,QACF,OAAO;AACL,0BAAgB;AAAA,YACd,GAAGA;AAAA,YACH,UAAU;AAAA,cACR,GAAGA,QAAO;AAAA,cACV,SAAS;AAAA,cACT,sBAAsB,kBAAkB;AAAA,cACxC,cAAc;AAAA,YAChB;AAAA,UACF;AAAA,QACF;AAAA,MACF,OAAO;AACL,QAAM,YAAI;AAAA,UACRD,KAAG;AAAA,YACD;AAAA,UACF;AAAA,QACF;AACA,wBAAgB;AAAA,UACd,GAAGC;AAAA,UACH,UAAU;AAAA,YACR,GAAGA,QAAO;AAAA,YACV,SAAS;AAAA,YACT,sBAAsB,kBAAkB;AAAA,YACxC,cAAc;AAAA,UAChB;AAAA,QACF;AAAA,MACF;AAEA,kBAAY;AACZ;AAAA,IACF;AAAA,IAEA,KAAK,aAAa;AAChB,YAAM,YAAY,MAAY,eAAO;AAAA,QACnC,SAAS;AAAA,QACT,SAAS;AAAA,UACP,EAAE,OAAO,SAAS,OAAO,UAAU,MAAM,uBAAuB;AAAA,UAChE,EAAE,OAAO,UAAU,OAAO,WAAW,MAAM,sBAAsB;AAAA,UACjE;AAAA,YACE,OAAO;AAAA,YACP,OAAO;AAAA,YACP,MAAM;AAAA,UACR;AAAA,UACA;AAAA,YACE,OAAO;AAAA,YACP,OAAO;AAAA,YACP,MAAM;AAAA,UACR;AAAA,UACA,EAAE,OAAO,SAAS,OAAO,UAAU,MAAM,0BAA0B;AAAA,UACnE;AAAA,YACE,OAAO;AAAA,YACP,OAAO;AAAA,YACP,MAAM;AAAA,UACR;AAAA,QACF;AAAA,QACA,cAAcA,QAAO,eAAe,oBAAoB;AAAA,MAC1D,CAAC;AAED,UAAU,iBAAS,SAAS,GAAG;AAC7B,QAAM,eAAO,oBAAoB;AACjC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,MAAM,YAAI;AAAA,QACRD,KAAG;AAAA,UACD;AAAA,QACF;AAAA,MACF;AACA,MAAM,YAAI;AAAA,QACRA,KAAG;AAAA,UACD;AAAA,QACF;AAAA,MACF;AAEA,sBAAgB;AAAA,QACd,GAAGC;AAAA,QACH,eAAe;AAAA,UACb,GAAGA,QAAO;AAAA,UACV,SAAS;AAAA,UACT,iBAAiB;AAAA,UACjB,kBAAkB;AAAA,QACpB;AAAA,MACF;AACA,kBAAY;AACZ;AAAA,IACF;AAAA,IAEA,KAAK,UAAU;AACb,YAAM,iBAAiB,MAAY,oBAAY;AAAA,QAC7C,SAAS;AAAA,QACT,SAAS;AAAA,UACP,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,oBAAoB;AAAA,UAC1D;AAAA,YACE,OAAO;AAAA,YACP,OAAO;AAAA,YACP,MAAM;AAAA,UACR;AAAA,UACA,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,yBAAyB;AAAA,UAC/D,EAAE,OAAO,SAAS,OAAO,SAAS,MAAM,yBAAyB;AAAA,UACjE,EAAE,OAAO,UAAU,OAAO,UAAU,MAAM,gBAAgB;AAAA,UAC1D;AAAA,YACE,OAAO;AAAA,YACP,OAAO;AAAA,YACP,MAAM;AAAA,UACR;AAAA,UACA,EAAE,OAAO,UAAU,OAAO,UAAU,MAAM,wBAAwB;AAAA,UAClE;AAAA,YACE,OAAO;AAAA,YACP,OAAO;AAAA,YACP,MAAM;AAAA,UACR;AAAA,UACA;AAAA,YACE,OAAO;AAAA,YACP,OAAO;AAAA,YACP,MAAM;AAAA,UACR;AAAA,UACA;AAAA,YACE,OAAO;AAAA,YACP,OAAO;AAAA,YACP,MAAM;AAAA,UACR;AAAA,QACF;AAAA,QACA,eAAeA,QAAO,eAAe,UAAU;AAAA,UAC7C;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,UAAU;AAAA,MACZ,CAAC;AAED,UAAU,iBAAS,cAAc,GAAG;AAClC,QAAM,eAAO,oBAAoB;AACjC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,sBAAgB;AAAA,QACd,GAAGA;AAAA,QACH,eAAe;AAAA,UACb,GAAGA,QAAO;AAAA,UACV,SAAS;AAAA,UACT,QAAQ;AAAA,QACV;AAAA,MACF;AACA,kBAAY;AACZ;AAAA,IACF;AAAA,IAEA,KAAK,gBAAgB;AACnB,YAAM,YAAY,MAAY,gBAAQ;AAAA,QACpC,SACE;AAAA,QACF,cAAc;AAAA,MAChB,CAAC;AAED,UAAU,iBAAS,SAAS,GAAG;AAC7B,QAAM,eAAO,oBAAoB;AACjC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,UAAI,CAAC,WAAW;AACd,QAAM,YAAI,KAAK,2BAA2B;AAC1C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,sBAAgB;AAAA,QACd,GAAGA;AAAA,QACH,aAAa;AAAA,MACf;AACA,kBAAY;AACZ;AAAA,IACF;AAAA,IAEA,KAAK,UAAU;AAEb,YAAM,EAAE,oBAAAG,oBAAmB,IAAI,MAAM;AAKrC,YAAM,eAAe,MAAMA,oBAAmBH,OAAM;AAGpD,sBAAgB,mBAAmBA,SAAQ,YAAY;AACvD,kBAAY;AACZ;AAAA,IACF;AAAA,EACF;AAGA,QAAM,cAAc,eAAe,eAAe,GAAM;AACxD,QAAM,WAAW,YAAY,MAAM,UAAU,gBAAgB,MAAM;AAEnE,UAAQ,IAAI;AAAA,EAAKD,KAAG,KAAK,cAAc,CAAC,EAAE;AAC1C,UAAQ;AAAA,IACN,cAAcA,KAAG,KAAK,GAAG,WAAW,gBAAgB,MAAM,OAAO,CAAC,KAAK,CAAC;AAAA,EAC1E;AACA,UAAQ;AAAA,IACN,cAAcA,KAAG,KAAK,GAAG,WAAW,YAAY,MAAM,OAAO,CAAC,KAAK,CAAC;AAAA,EACtE;AACA,MAAI,WAAW,GAAG;AAChB,YAAQ,IAAI,cAAcA,KAAG,OAAO,IAAI,WAAW,QAAQ,CAAC,KAAK,CAAC,EAAE;AAAA,EACtE,WAAW,WAAW,GAAG;AACvB,YAAQ;AAAA,MACN,cAAcA,KAAG,MAAM,GAAG,WAAW,KAAK,IAAI,QAAQ,CAAC,CAAC,KAAK,CAAC;AAAA,IAChE;AAAA,EACF;AACA,UAAQ,IAAI,EAAE;AAGd,MAAI,EAAE,QAAQ,OAAO,QAAQ,UAAU;AACrC,UAAM,YAAY,MAAY,gBAAQ;AAAA,MACpC,SAAS;AAAA,MACT,cAAc;AAAA,IAChB,CAAC;AAED,QAAU,iBAAS,SAAS,KAAK,CAAC,WAAW;AAC3C,MAAM,eAAO,oBAAoB;AACjC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAGA,MAAI;AACJ,MAAI,SAAS,aAAa,YAAY,CAAC,SAAS,QAAQ;AACtD,mBAAe,MAAM,mBAAmB;AAAA,EAC1C,WAAW,SAAS,aAAa,UAAU;AACzC,mBAAe,SAAS;AAAA,EAC1B;AAGA,QAAM,cAAgC;AAAA,IACpC,UAAU,SAAS;AAAA,IACnB;AAAA,IACA,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAGA,MAAI,QAAQ,SAAS;AAEnB,QAAI;AACF,YAAM,gBAAgB,MAAM,SAAS;AAAA,QACnC;AAAA,QACA,YAAY;AACV,gBAAM,oBAAoB;AAE1B,gBAAM,QACJ,MAAa,oBAAW,eAAe;AAAA,YACrC;AAAA,cACE,WACE,SAAS,SAAS,OAAO,mBACzB,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,cACvC,aAAa;AAAA,cACb,SAAS,YAAY;AACnB,sBAAMK,UAAS,MAAM,iBAAiB,WAAW;AACjD,uBAAO;AAAA,kBACL,SAASA,QAAO;AAAA,kBAChB,eAAeA,QAAO;AAAA,kBACtB,WAAWA,QAAO;AAAA,kBAClB,QAAQA,QAAO;AAAA,kBACf,iBAAiBA,QAAO;AAAA,kBACxB,QAAQA,QAAO;AAAA,kBACf,YAAYA,QAAO;AAAA,kBACnB,sBAAsBA,QAAO;AAAA,kBAC7B,sBAAsBA,QAAO;AAAA,kBAC7B,kBAAkBA,QAAO;AAAA,kBACzB,iCACEA,QAAO;AAAA,kBACT,YAAYA,QAAO;AAAA,kBACnB,kBAAkBA,QAAO;AAAA,kBACzB,kBAAkBA,QAAO;AAAA,gBAC3B;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,SAAS,iBAAiB;AAAA,cAC1B,SAAS;AAAA,gBACP,0BAA0B;AAAA,gBAC1B,YAAY;AAAA,cACd;AAAA,cACA,iBAAiB;AAAA,YACnB;AAAA,UACF;AAEF,gBAAM,MAAM,UAAU,cAAc,EAAE,OAAO,OAAO,CAAC;AAGrD,gBAAM,MAAM,QAAQ,EAAE,UAAU,MAAM;AAAA,UAAC,EAAE,CAAC;AAG1C,gBAAM,SAAS,MAAM,MAAM,QAAQ,EAAE,MAAM,KAAK,CAAC;AACjD,iBAAO;AAAA,QACT;AAAA,MACF;AAGA,YAAM,iBAAiB;AAAA,QACrB,YAAY,WAAW,gBAAgB,MAAM,OAAO,CAAC;AAAA,QACrD,kBAAkB,WAAW,YAAY,MAAM,OAAO,CAAC;AAAA,QACvD,WAAW,IACP,YAAY,WAAW,QAAQ,CAAC,QAChC,WAAW,IACT,YAAY,WAAW,KAAK,IAAI,QAAQ,CAAC,CAAC,QAC1C;AAAA,MACR,EAAE,KAAK,IAAI;AAGX,qBAAe;AAAA,QACb,eAAe,cAAc;AAAA,QAC7B,cAAc;AAAA,QACd,aAAa;AAAA,MACf,CAAC;AAED,MAAM;AAAA,QACJL,KAAG,MAAM,qDAAqD;AAAA,MAChE;AAGA,0BAAoB,SAAS;AAAA,QAC3B,aAAa,SAAS,SAAS,OAAO;AAAA,QACtC,WAAW;AAAA,QACX,SAAS;AAAA,QACT,QAAQ,OAAO,kBAAkB,WAAW,gBAAgB;AAAA,QAC5D,aAAa,KAAK,IAAI,IAAI;AAAA,MAC5B,CAAC;AACD;AAAA,IACF,SAAS,OAAY;AACnB,iBAAW,kBAAkB,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACjE,UAAI,MAAM,SAAS,SAAS,2BAA2B,GAAG;AACxD,cAAM,OAAO,YAAY;AAAA,MAC3B;AACA,YAAM,IAAI,MAAM,mBAAmB,MAAM,OAAO,EAAE;AAAA,IACpD;AAAA,EACF;AAGA,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,SAAS;AAAA,MACvB;AAAA,MACA,YAAY;AACV,cAAM,oBAAoB;AAE1B,cAAM,QACJ,MAAa,oBAAW,eAAe;AAAA,UACrC;AAAA,YACE,WACE,SAAS,SAAS,OAAO,mBACzB,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,YACvC,aAAa;AAAA,YACb,SAAS,YAAY;AACnB,oBAAM,SAAS,MAAM,iBAAiB,WAAW;AAEjD,qBAAO;AAAA,gBACL,SAAS,OAAO;AAAA,gBAChB,eAAe,OAAO;AAAA,gBACtB,WAAW,OAAO;AAAA,gBAClB,QAAQ,OAAO;AAAA,gBACf,iBAAiB,OAAO;AAAA,gBACxB,QAAQ,OAAO;AAAA,gBACf,YAAY,OAAO;AAAA,gBACnB,sBAAsB,OAAO;AAAA,gBAC7B,sBAAsB,OAAO;AAAA,gBAC7B,kBAAkB,OAAO;AAAA,gBACzB,iCACE,OAAO;AAAA,gBACT,YAAY,OAAO;AAAA,gBACnB,kBAAkB,OAAO;AAAA,gBACzB,kBAAkB,OAAO;AAAA,cAC3B;AAAA,YACF;AAAA,UACF;AAAA,UACA;AAAA,YACE,SAAS,iBAAiB;AAAA,YAC1B,SAAS;AAAA,cACP,0BAA0B;AAAA,cAC1B,YAAY;AAAA,YACd;AAAA,YACA,iBAAiB;AAAA,UACnB;AAAA,QACF;AAEF,cAAM,MAAM,UAAU;AAAA,UACpB,SAAS,SAAS,OAAO,mBACvB,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,QACzC;AACA,cAAM,MAAM,UAAU,cAAc,EAAE,OAAO,OAAO,CAAC;AAIrD,cAAM,MAAM,QAAQ,EAAE,UAAU,MAAM;AAAA,QAAC,EAAE,CAAC;AAG1C,cAAM,WAAW,MAAM,MAAM,GAAG,EAAE,UAAU,MAAM;AAAA,QAAC,EAAE,CAAC;AACtD,cAAM,gBAAgB,SAAS;AAE/B,eAAO;AAAA,UACL,SAAS,cAAc,SAAS;AAAA,UAChC,eAAe,cAAc,eAAe;AAAA,UAG5C,WAAW,cAAc,WAAW;AAAA,UACpC,QAAQ,cAAc,QAAQ;AAAA,UAC9B,iBAAiB,cAAc,iBAAiB;AAAA,UAGhD,QAAQ,cAAc,QAAQ;AAAA,UAC9B,YAAY,cAAc,YAAY;AAAA,UACtC,sBAAsB,cAAc,sBAAsB;AAAA,UAG1D,sBAAsB,cAAc,sBAAsB;AAAA,UAG1D,kBAAkB,cAAc,kBAAkB;AAAA,UAGlD,iCAAiC,cAC9B,iCAAiC;AAAA,UAGpC,YAAY,cAAc,YAAY;AAAA,UACtC,kBAAkB,cAAc,kBAAkB;AAAA,UAGlD,kBAAkB,cAAc,kBAAkB;AAAA,QAGpD;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAY;AAEnB,wBAAoB,SAAS;AAAA,MAC3B,aAAa,SAAS,SAAS,OAAO;AAAA,MACtC,WAAW;AAAA,MACX,QAAQ,OAAO,kBAAkB,WAAW,gBAAgB;AAAA,MAC5D,aAAa,KAAK,IAAI,IAAI;AAAA,IAC5B,CAAC;AAGD,QAAI,MAAM,SAAS,SAAS,2BAA2B,GAAG;AACxD,iBAAW,gBAAgB,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC9D,YAAM,OAAO,YAAY;AAAA,IAC3B;AAEA,eAAW,kBAAkB,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAChE,UAAM,IAAI,MAAM,0BAA0B,MAAM,OAAO,EAAE;AAAA,EAC3D;AAGA,MAAI,QAAQ,UAAU,QAAQ,cAAc,QAAQ,WAAW,SAAS,GAAG;AACzE,UAAM,EAAE,gBAAAG,iBAAgB,kBAAAG,kBAAiB,IAAI,MAAM;AAGnD,UAAM,aAAa,MAAMH,gBAAe,QAAQ,QAAQ,MAAM;AAE9D,QAAI,YAAY;AACd,UAAI;AACF,iBAAS,MAAM,iCAAiC;AAGhD,cAAM,iBACJ,cAAc,kBAAkB,QAAQ,QAAQ,MAAM;AAExD,cAAMG;AAAA,UACJ,WAAW;AAAA,UACX,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ;AAAA,QACV;AACA,iBAAS,QAAQ,gCAAgC;AAAA,MACnD,SAAS,OAAY;AACnB,iBAAS;AAAA,UACP,+CAA+C,MAAM,OAAO;AAAA,QAC9D;AACA,iBAAS;AAAA,UACP;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,oBAAkB,UAAU,aAAa;AACzC,MAAI,SAAS,SAAS,OAAO;AAC3B,aAAS,SAAS,MAAM,SAAS;AAAA,EACnC;AACA,QAAM,uBAAuB,QAAQ;AAErC,WAAS,KAAK,6BAA6B;AAG3C,QAAM,2BAA2B,CAAC;AAClC,QAAM,uBAAuB,CAAC;AAE9B,MAAI,QAAQ,sBAAsB;AAGhC,QAAI,QAAQ,sBAAsB;AAEhC,UAAI,QAAQ,kBAAkB;AAC5B,iCAAyB,KAAK;AAAA,UAC5B,MAAM,QAAQ;AAAA,UACd,MAAM;AAAA,UACN,OAAO,QAAQ;AAAA,QACjB,CAAC;AAAA,MACH;AAAA,IACF,OAAO;AAEL,+BAAyB,KAAK;AAAA,QAC5B,MAAM,QAAQ;AAAA,QACd,MAAM;AAAA,QACN,OAAO,KAAK,QAAQ,MAAM;AAAA,MAC5B,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,QAAQ,wBAAwB,QAAQ,iCAAiC;AAC3E,yBAAqB,KAAK,GAAG,QAAQ,+BAA+B;AAAA,EACtE;AAGA,QAAM,6BACJ,QAAQ,wBACR,qBAAqB,SAAS,KAC9B,CAAC,QAAQ;AAGX,iBAAe;AAAA,IACb,SAAS,QAAQ;AAAA,IACjB,eAAe,QAAQ;AAAA,IACvB,QAAQ,QAAQ;AAAA,IAChB,WAAW,QAAQ;AAAA,IACnB,0BACE,yBAAyB,SAAS,IAC9B,2BACA;AAAA,IACN,sBACE,qBAAqB,SAAS,IAAI,uBAAuB;AAAA,IAC3D,sBAAsB,QAAQ;AAAA,IAC9B,sBAAsB,QAAQ;AAAA,EAChC,CAAC;AAGD,UAAQ,IAAI;AAAA,EAAKN,KAAG,MAAM,QAAG,CAAC,IAAIA,KAAG,KAAK,mBAAmB,CAAC;AAAA,CAAI;AAElE,MAAI,kBAAkB,YAAY,WAAW;AAC3C,YAAQ;AAAA,MACN,eAAeA,KAAG,KAAK,SAAS,CAAC,YAAYA,KAAG,MAAM,GAAG,WAAW,YAAY,MAAM,OAAO,CAAC,KAAK,CAAC;AAAA;AAAA,IACtG;AAAA,EACF,OAAO;AACL,YAAQ;AAAA,MACN,0BAA0BA,KAAG,MAAM,GAAG,WAAW,YAAY,MAAM,OAAO,CAAC,KAAK,CAAC;AAAA;AAAA,IACnF;AAAA,EACF;AAGA,MAAI,4BAA4B;AAC9B,YAAQ,IAAIA,KAAG,KAAK,8CAAoC,CAAC;AACzD,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ;AAAA,MACN,YAAYA,KAAG,KAAK,qBAAqB,CAAC;AAAA;AAAA,IAC5C;AACA,YAAQ;AAAA,MACNA,KAAG;AAAA,QACD;AAAA,MACF;AAAA,IACF;AAAA,EACF,WAAW,QAAQ,wBAAwB,QAAQ,kBAAkB;AACnE,YAAQ;AAAA,MACNA,KAAG,MAAM,QAAG,IACV,MACAA,KAAG,KAAK,wDAAwD;AAAA,IACpE;AAAA,EACF;AAGA,QAAM,kBAA4B,CAAC;AACnC,MAAI,cAAc,UAAU,QAAS,iBAAgB,KAAK,UAAU;AACpE,MAAI,cAAc,iBAAiB;AACjC,oBAAgB,KAAK,kBAAkB;AACzC,MAAI,cAAc,eAAe;AAC/B,oBAAgB,KAAK,gBAAgB;AACvC,MAAI,cAAc,eAAe;AAC/B,oBAAgB,KAAK,kBAAkB;AACzC,MAAI,cAAc,YAAa,iBAAgB,KAAK,cAAc;AAClE,MAAI,cAAc,gBAAgB;AAChC,oBAAgB,KAAK,iBAAiB;AAExC,sBAAoB,SAAS;AAAA,IAC3B,aAAa,SAAS,SAAS,OAAO;AAAA,IACtC,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,QAAQ,OAAO,kBAAkB,WAAW,gBAAgB;AAAA,IAC5D,aAAa,KAAK,IAAI,IAAI;AAAA,EAC5B,CAAC;AACH;;;ACxqCA;AAAA,YAAYO,aAAW;AACvB,YAAYC,cAAY;AACxB,OAAO,aAAa;AACpB,OAAO,UAAU;AACjB,OAAOC,UAAQ;;;ACJf;AAAA,OAAO,YAAY;AACnB,OAAOC,WAAU;AACjB,SAAS,iBAAAC,sBAAqB;AAC9B,OAAO,aAAa;AACpB,SAAS,4BAA4B;;;ACJrC;AAKO,SAAS,kBAAkB,eAAuB;AACvD,SAAO,CAAC,KAAc,KAAe,SAAuB;AAE1D,UAAM,QAAQ,IAAI,MAAM,SAAS,IAAI,QAAQ,cAAc;AAE3D,QAAI,CAAC,SAAS,UAAU,eAAe;AACrC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,IACvD;AAEA,SAAK;AAAA,EACP;AACF;;;AChBA;AAKO,SAAS,aACd,KACA,MACA,KACA,OACA;AACA,UAAQ,MAAM,iBAAiB,GAAG;AAElC,MAAI,OAAO,GAAG,EAAE,KAAK;AAAA,IACnB,OAAO;AAAA,IACP,SAAS,IAAI;AAAA,EACf,CAAC;AACH;;;ACjBA;AACA,SAAS,UAAU,oBAAoB;;;ACDvC;AAEA;AAFA,SAAS,qBAAqB,aAAAC,kBAAiB;AAC/C,SAAS,2BAAAC,0BAAyB,eAAAC,oBAAmB;AAmBrD,eAAsB,eACpB,SACA,QACoB;AAEpB,QAAM,cAAc,UAAU,MAAM,WAAW,SAAS,MAAM,IAAI;AAClE,QAAM,MAAM,IAAIF,WAAU,EAAE,QAAQ,YAAY,CAAC;AAEjD,QAAM,WAAW,MAAM,IAAI,KAAK,IAAI,oBAAoB,CAAC,CAAC,CAAC;AAE3D,SAAO;AAAA,IACL,eAAe,SAAS,iBAAiB;AAAA,IACzC,aAAa,SAAS,eAAe;AAAA,IACrC,iBAAiB,SAAS,mBAAmB;AAAA,EAC/C;AACF;AAKA,eAAsB,gBACpB,SACA,QACA,QACqB;AAErB,QAAM,cAAc,UAAU,MAAM,WAAW,SAAS,MAAM,IAAI;AAClE,QAAMG,SAAQ,IAAID,aAAY,EAAE,QAAQ,YAAY,CAAC;AAErD,QAAM,WAAW,MAAMC,OAAM;AAAA,IAC3B,IAAIF,yBAAwB;AAAA,MAC1B,eAAe;AAAA,IACjB,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL;AAAA,IACA,UAAU,SAAS,4BAA4B;AAAA,IAC/C,YAAY,SAAS,gBAAgB,UAAU;AAAA,IAC/C,YAAY,SAAS,gBAAgB,UAAU,CAAC;AAAA,EAClD;AACF;;;ADxDO,SAAS,oBAAoBG,SAA8B;AAChE,QAAM,SAAS,aAAa;AAK5B,SAAO,IAAI,YAAY,OAAO,KAAc,QAAkB;AAC5D,QAAI;AACF,YAAM,EAAE,OAAO,IAAI,IAAI;AAEvB,UAAI,CAAC,QAAQ;AACX,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,MACpE;AAEA,YAAM,aAAa,MAAM;AAAA,QACvBA,QAAO;AAAA,QACPA,QAAO;AAAA,QACP;AAAA,MACF;AAEA,UAAI,KAAK,UAAU;AAAA,IACrB,SAAS,OAAgB;AACvB,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,IAC9C;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;AElCA;AACA,SAAS,UAAUC,qBAAoB;;;ACDvC;AAAA;AAAA,EACE,kBAAAC;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAkE3B,eAAsB,eACpB,SACqB;AACrB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAMC,YAAW,IAAID,gBAAe,EAAE,OAAO,CAAC;AAE9C,MAAI;AAEF,QAAI,QAAe,CAAC;AACpB,QAAI,WAAW;AACb,UAAI,yBAAyB;AAC7B,YAAM,4BAAiD;AAAA,QACrD,cAAc,EAAE,GAAG,UAAU;AAAA,MAC/B;AAGA,UAAI,aAAa,SAAS;AACxB,kCAA0B;AAC1B,kCAA0B,YAAY,IAAI,EAAE,GAAG,UAAU,SAAS,EAAE;AACpE,kCAA0B,UAAU,IAAI,EAAE,GAAG,QAAQ,SAAS,EAAE;AAAA,MAClE,WAAW,WAAW;AACpB,kCAA0B;AAC1B,kCAA0B,YAAY,IAAI,EAAE,GAAG,UAAU,SAAS,EAAE;AAAA,MACtE;AAEA,YAAM,WAAW,MAAMC,UAAS;AAAA,QAC9B,IAAI,aAAa;AAAA,UACf,WAAW;AAAA,UACX,WAAW;AAAA,UACX,wBAAwB;AAAA,UACxB,2BAA2B;AAAA,UAC3B,kBAAkB;AAAA;AAAA,QACpB,CAAC;AAAA,MACH;AAEA,cAAQ,SAAS,SAAS,CAAC;AAAA,IAC7B,OAAO;AAEL,YAAM,WAAW,MAAMA,UAAS;AAAA,QAC9B,IAAI,YAAY;AAAA,UACd,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAEA,cAAQ,SAAS,SAAS,CAAC;AAAA,IAC7B;AAGA,UAAM,eAAe,MAAM,IAAI,CAAC,SAAS,WAAW,IAAI,CAAC;AAGzD,UAAM,WAAW,oBAAI,IAAiB;AAEtC,eAAW,QAAQ,cAAc;AAC/B,YAAM,YAAY,KAAK;AACvB,YAAM,WAAW,SAAS,IAAI,SAAS;AAEvC,UAAI,UAAU;AAGZ,cAAM,kBAAkB,iBAAiB,IAAI;AAC7C,cAAM,mBAAmB,iBAAiB,QAAQ;AAElD,YAAI,kBAAkB,kBAAkB;AACtC,mBAAS,IAAI,WAAW,IAAI;AAAA,QAC9B;AAAA,MACF,OAAO;AACL,iBAAS,IAAI,WAAW,IAAI;AAAA,MAC9B;AAAA,IACF;AAGA,UAAM,OAAO,MAAM,KAAK,SAAS,OAAO,CAAC,EACtC,IAAI,iBAAiB,EACrB,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAGrC,WAAO,KAAK,MAAM,GAAG,KAAK;AAAA,EAC5B,SAAS,OAAO;AACd,YAAQ,MAAM,8BAA8B,KAAK;AACjD,UAAM;AAAA,EACR;AACF;AAMA,SAAS,iBAAiB,MAAmB;AAC3C,QAAM,OAAO,KAAK,WAAW,YAAY;AAEzC,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,IACT,KAAK,UAAU;AAGb,YAAM,aAAa,KAAK,YAAY,YAAY;AAChD,aAAO,eAAe,cAAc,IAAI;AAAA,IAC1C;AAAA,IACA,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKA,SAAS,kBAAkB,MAAqB;AAE9C,MAAIC,UAA6B;AACjC,QAAM,YAAY,KAAK,WAAW,YAAY;AAE9C,MAAI,cAAc,aAAa;AAC7B,IAAAA,UAAS;AAAA,EACX,WAAW,cAAc,UAAU;AACjC,IAAAA,UAAS;AAAA,EACX,WAAW,cAAc,SAAS;AAChC,IAAAA,UAAS;AAAA,EACX,WAAW,cAAc,QAAQ;AAC/B,IAAAA,UAAS;AAAA,EACX,WAAW,cAAc,YAAY;AACnC,IAAAA,UAAS;AAAA,EACX,WAAW,cAAc,QAAQ;AAC/B,IAAAA,UAAS;AAAA,EACX,WAAW,KAAK,cAAc;AAC5B,IAAAA,UAAS;AAAA,EACX;AAIA,MAAI,cAAwB,CAAC;AAC7B,QAAM,UAAU,KAAK,MAAM,KAAK;AAEhC,MAAI,SAAS;AACX,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA,QAAQ,aAAa;AAAA,IACvB;AAEA,QAAI,mBAAmB,KAAK;AAE1B,oBAAc,MAAM,KAAK,OAAO;AAAA,IAClC,WAAW,MAAM,QAAQ,OAAO,GAAG;AACjC,oBAAc;AAAA,IAChB,WAAW,OAAO,YAAY,UAAU;AACtC,oBAAc,CAAC,OAAO;AAAA,IACxB;AAAA,EACF;AAEA,UAAQ,IAAI,2BAA2B,WAAW;AAElD,SAAO;AAAA,IACL,WAAW,KAAK;AAAA,IAChB,IAAI;AAAA,IACJ,MAAM,KAAK,QAAQ;AAAA,IACnB,SAAS,KAAK,WAAW;AAAA,IACzB,QAAAA;AAAA,IACA,QAAQ,OAAO,KAAK,MAAM;AAAA,IAC1B,WAAW,KAAK;AAAA,IAChB,cAAc,KAAK;AAAA,EACrB;AACF;AAKA,eAAsB,eACpB,WACA,SAC8B;AAC9B,QAAM,EAAE,QAAQ,UAAU,IAAI;AAC9B,QAAMD,YAAW,IAAID,gBAAe,EAAE,OAAO,CAAC;AAE9C,MAAI;AAEF,UAAM,WAAW,MAAMC,UAAS;AAAA,MAC9B,IAAI,aAAa;AAAA,QACf,WAAW;AAAA,QACX,wBAAwB;AAAA,QACxB,2BAA2B;AAAA,UACzB,cAAc,EAAE,GAAG,UAAU;AAAA,QAC/B;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,QAAQ,SAAS,SAAS,CAAC;AAEjC,QAAI,MAAM,WAAW,GAAG;AACtB,aAAO;AAAA,IACT;AAGA,UAAM,SAAS,MAAM,IAAI,CAAC,SAAS,WAAW,IAAI,CAAC;AAGnD,UAAM,YAAY,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,YAAY,MAAM,MAAM;AAE1E,QAAI,CAAC,WAAW;AACd,aAAO;AAAA,IACT;AAEA,YAAQ,IAAI,sBAAsB;AAAA,MAChC,MAAM,UAAU;AAAA,MAChB,QAAQ,UAAU;AAAA,MAClB,SAAS,UAAU;AAAA,MACnB,IAAI,UAAU;AAAA,MACd,aAAa,UAAU;AAAA,MACvB,eAAe,OAAO,KAAK,SAAS;AAAA,IACtC,CAAC;AAGD,QAAI;AACJ,QAAI;AAEJ,QAAI,UAAU,WAAW;AACvB,UAAI;AACF,cAAM,YAAY,KAAK,MAAM,UAAU,SAAS;AAChD,gBAAQ,IAAI,yBAAyB,OAAO,KAAK,SAAS,CAAC;AAI3D,YAAI,UAAU,SAAS;AACrB,qBAAW,UAAU,QAAQ;AAC7B,qBAAW,UAAU,QAAQ;AAAA,QAC/B;AAGA,YAAI,UAAU,MAAM,SAAS;AAC3B,qBAAW,UAAU,KAAK,QAAQ;AAClC,qBAAW,UAAU,KAAK,QAAQ;AAAA,QACpC;AAAA,MACF,SAAS,GAAG;AACV,gBAAQ,MAAM,8BAA8B,CAAC;AAAA,MAC/C;AAAA,IACF;AAGA,QAAI,cAAwB,CAAC;AAC7B,UAAM,UAAU,UAAU,MAAM,UAAU;AAE1C,QAAI,SAAS;AACX,UAAI,mBAAmB,KAAK;AAC1B,sBAAc,MAAM,KAAK,OAAO;AAAA,MAClC,WAAW,MAAM,QAAQ,OAAO,GAAG;AACjC,sBAAc;AAAA,MAChB,WAAW,OAAO,YAAY,UAAU;AACtC,sBAAc,CAAC,OAAO;AAAA,MACxB;AAAA,IACF;AAGA,QAAIC,UAAiC;AACrC,UAAM,cAAc,OAAO;AAAA,MACzB,CAAC,MAAM,EAAE,WAAW,YAAY,MAAM;AAAA,IACxC;AACA,UAAM,YAAY,OAAO;AAAA,MACvB,CAAC,MAAM,EAAE,WAAW,YAAY,MAAM;AAAA,IACxC;AACA,UAAM,eAAe,OAAO;AAAA,MAC1B,CAAC,MAAM,EAAE,WAAW,YAAY,MAAM;AAAA,IACxC;AACA,UAAM,UAAU,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,YAAY,MAAM,MAAM;AACxE,UAAM,WAAW,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,YAAY,MAAM,OAAO;AAE1E,QAAI,cAAc;AAChB,MAAAA,UAAS;AAAA,IACX,WAAW,WAAW;AACpB,MAAAA,UAAS;AAAA,IACX,WAAW,UAAU;AACnB,MAAAA,UAAS;AAAA,IACX,WAAW,SAAS;AAClB,MAAAA,UAAS;AAAA,IACX,WAAW,aAAa;AACtB,MAAAA,UAAS;AAAA,IACX;AAGA,UAAM,WAAyB,OAC5B,IAAI,CAAC,UAAU;AACd,YAAM,YAAY,MAAM,WAAW,YAAY;AAC/C,UAAI,OAA2B;AAE/B,cAAQ,WAAW;AAAA,QACjB,KAAK;AACH,iBAAO;AACP;AAAA,QACF,KAAK;AACH,iBAAO;AACP;AAAA,QACF,KAAK;AACH,iBAAO;AACP;AAAA,QACF,KAAK;AACH,iBAAO;AACP;AAAA,QACF,KAAK;AACH,iBAAO;AACP;AAAA,QACF,KAAK;AACH,iBAAO;AACP;AAAA,QACF;AACE,iBAAO;AAAA,MACX;AAEA,YAAM,WAAgC,CAAC;AAGvC,UAAI,cAAc,YAAY,MAAM,YAAY;AAC9C,iBAAS,aAAa,MAAM;AAC5B,iBAAS,gBAAgB,MAAM;AAAA,MACjC;AAEA,UAAI,cAAc,eAAe,MAAM,uBAAuB;AAC5D,iBAAS,eAAe,MAAM;AAAA,MAChC;AAEA,UAAI,cAAc,WAAW,MAAM,MAAM;AACvC,iBAAS,OAAO,MAAM;AAAA,MACxB;AAEA,UAAI,MAAM,WAAW;AACnB,iBAAS,YAAY,MAAM;AAAA,MAC7B;AAEA,aAAO;AAAA,QACL;AAAA,QACA,WAAW,OAAO,MAAM,UAAU,MAAM,SAAS;AAAA,QACjD,UAAU,OAAO,KAAK,QAAQ,EAAE,SAAS,IAAI,WAAW;AAAA,MAC1D;AAAA,IACF,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAE3C,WAAO;AAAA,MACL,IAAI;AAAA,MACJ;AAAA,MACA,MAAM,UAAU,QAAQ;AAAA,MACxB,IAAI;AAAA,MACJ,SAAS,UAAU;AAAA,MACnB,SAAS,UAAU,WAAW;AAAA,MAC9B,UAAU,YAAY,UAAU;AAAA,MAChC,UAAU,YAAY,UAAU;AAAA,MAChC,QAAAA;AAAA,MACA,QAAQ,OAAO,UAAU,MAAM;AAAA,MAC/B,QAAQ;AAAA,IACV;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,+BAA+B,KAAK;AAClD,UAAM;AAAA,EACR;AACF;;;ADrbO,SAAS,mBAAmBC,SAA8B;AAC/D,QAAM,SAASC,cAAa;AAK5B,SAAO,IAAI,KAAK,OAAO,KAAc,QAAkB;AACrD,QAAI;AACF,cAAQ,IAAI,6BAA6B;AACzC,cAAQ,IAAI,iBAAiB,IAAI,KAAK;AACtC,cAAQ,IAAI,WAAW;AAAA,QACrB,WAAWD,QAAO;AAAA,QAClB,QAAQA,QAAO;AAAA,QACf,WAAWA,QAAO;AAAA,MACpB,CAAC;AAGD,YAAM,QAAQ,IAAI,MAAM,QACpB,OAAO,SAAS,IAAI,MAAM,OAAiB,EAAE,IAC7C;AACJ,YAAM,YAAY,IAAI,MAAM,YACxB,OAAO,SAAS,IAAI,MAAM,WAAqB,EAAE,IACjD;AACJ,YAAM,UAAU,IAAI,MAAM,UACtB,OAAO,SAAS,IAAI,MAAM,SAAmB,EAAE,IAC/C;AAEJ,UAAI,CAACA,QAAO,WAAW;AACrB,gBAAQ,IAAI,0BAA0B;AACtC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UAC1B,OACE;AAAA,QACJ,CAAC;AAAA,MACH;AAEA,cAAQ,IAAI,sCAAsC;AAClD,YAAM,OAAO,MAAM,eAAe;AAAA,QAChC,QAAQA,QAAO;AAAA,QACf,WAAWA,QAAO;AAAA,QAClB,WAAWA,QAAO;AAAA,QAClB;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,cAAQ,IAAI,SAAS,KAAK,MAAM,aAAa;AAC7C,UAAI,KAAK,EAAE,KAAK,CAAC;AAAA,IACnB,SAAS,OAAgB;AACvB,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,cAAQ,MAAM,8BAA8B,KAAK;AACjD,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,IAC9C;AAAA,EACF,CAAC;AAKD,SAAO,IAAI,QAAQ,OAAO,KAAc,QAAkB;AACxD,QAAI;AACF,YAAM,EAAE,GAAG,IAAI,IAAI;AACnB,cAAQ,IAAI,yCAAyC,EAAE;AACvD,cAAQ,IAAI,oBAAoB,IAAI,OAAO;AAC3C,cAAQ,IAAI,kBAAkB,IAAI,KAAK;AAEvC,UAAI,CAACA,QAAO,WAAW;AACrB,gBAAQ,IAAI,0BAA0B;AACtC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UAC1B,OACE;AAAA,QACJ,CAAC;AAAA,MACH;AAEA,cAAQ,IAAI,yCAAyC;AACrD,YAAM,QAAQ,MAAM,eAAe,IAAI;AAAA,QACrC,QAAQA,QAAO;AAAA,QACf,WAAWA,QAAO;AAAA,MACpB,CAAC;AAED,UAAI,CAAC,OAAO;AACV,gBAAQ,IAAI,2BAA2B,EAAE;AACzC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MAC1D;AAEA,cAAQ,IAAI,wBAAwB,MAAM,SAAS;AACnD,cAAQ,IAAI,yBAAyB,MAAM,OAAO,QAAQ,QAAQ;AAClE,UAAI,KAAK,KAAK;AAAA,IAChB,SAAS,OAAgB;AACvB,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,cAAQ,MAAM,iCAAiC,KAAK;AACpD,cAAQ;AAAA,QACN;AAAA,QACA,iBAAiB,QAAQ,MAAM,QAAQ;AAAA,MACzC;AACA,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,IAC9C;AAAA,EACF,CAAC;AAKD,SAAO,IAAI,gBAAgB,OAAO,KAAc,QAAkB;AAChE,QAAI;AACF,YAAM,EAAE,GAAG,IAAI,IAAI;AACnB,cAAQ,IAAI,mDAAmD,EAAE;AAEjE,UAAI,CAACA,QAAO,kBAAkB;AAC5B,gBAAQ,IAAI,6BAA6B;AACzC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UAC1B,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,UAAI,CAACA,QAAO,YAAY;AACtB,gBAAQ,IAAI,2BAA2B;AACvC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UAC1B,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,UAAI,CAACA,QAAO,WAAW;AACrB,gBAAQ,IAAI,0BAA0B;AACtC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UAC1B,OACE;AAAA,QACJ,CAAC;AAAA,MACH;AAGA,cAAQ,IAAI,0CAA0C;AACtD,YAAM,eAAe,MAAM,eAAe,IAAI;AAAA,QAC5C,QAAQA,QAAO;AAAA,QACf,WAAWA,QAAO;AAAA,MACpB,CAAC;AAED,UAAI,CAAC,cAAc;AACjB,gBAAQ,IAAI,gDAAgD,EAAE;AAC9D,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UAC1B,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,cAAQ,IAAI,8CAA8C;AAC1D,YAAM,EAAE,oBAAAE,oBAAmB,IAAI,MAAM;AAGrC,YAAM,gBAAgB,MAAMA,oBAAmB,IAAI;AAAA,QACjD,QAAQF,QAAO;AAAA,QACf,YAAYA,QAAO;AAAA,QACnB,MAAM,aAAa;AAAA,QACnB,IAAI,aAAa,GAAG,CAAC;AAAA;AAAA,QACrB,SAAS,aAAa;AAAA,QACtB,WAAW,IAAI,KAAK,aAAa,MAAM;AAAA,MACzC,CAAC;AAED,UAAI,CAAC,eAAe;AAClB,gBAAQ,IAAI,4CAA4C,EAAE;AAC1D,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UAC1B,OACE;AAAA,QACJ,CAAC;AAAA,MACH;AAEA,cAAQ,IAAI,yBAAyB,cAAc,SAAS;AAC5D,UAAI,KAAK,aAAa;AAAA,IACxB,SAAS,OAAgB;AACvB,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,cAAQ,MAAM,kCAAkC,KAAK;AACrD,cAAQ;AAAA,QACN;AAAA,QACA,iBAAiB,QAAQ,MAAM,QAAQ;AAAA,MACzC;AACA,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,IAC9C;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;AExLA;AACA,SAAS,UAAUG,qBAAoB;;;ACDvC;AAKA;AALA;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAeP,eAAsB,gBACpB,SACA,QACA,WACA,WACsB;AAEtB,QAAM,cAAc,UAAU,MAAM,WAAW,SAAS,MAAM,IAAI;AAGlE,QAAMC,cAAa,IAAI,iBAAiB,EAAE,QAAQ,YAAY,CAAC;AAG/D,QAAM,UAA6B;AAAA,IACjC;AAAA,MACE,IAAI;AAAA,MACJ,YAAY;AAAA,QACV,QAAQ;AAAA,UACN,WAAW;AAAA,UACX,YAAY;AAAA,QACd;AAAA,QACA,QAAQ;AAAA;AAAA,QACR,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,YAAY;AAAA,QACV,QAAQ;AAAA,UACN,WAAW;AAAA,UACX,YAAY;AAAA,QACd;AAAA,QACA,QAAQ;AAAA,QACR,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,YAAY;AAAA,QACV,QAAQ;AAAA,UACN,WAAW;AAAA,UACX,YAAY;AAAA,QACd;AAAA,QACA,QAAQ;AAAA,QACR,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,YAAY;AAAA,QACV,QAAQ;AAAA,UACN,WAAW;AAAA,UACX,YAAY;AAAA,QACd;AAAA,QACA,QAAQ;AAAA,QACR,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,MAAMA,YAAW;AAAA,IAChC,IAAI,qBAAqB;AAAA,MACvB,mBAAmB;AAAA,MACnB,WAAW,UAAU;AAAA,MACrB,SAAS,UAAU;AAAA,IACrB,CAAC;AAAA,EACH;AAGA,QAAM,UAAU,SAAS,qBAAqB,CAAC;AAE/C,QAAM,cAAc,CAAC,OAAe;AAClC,UAAM,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC9C,QAAI,EAAE,QAAQ,cAAc,OAAO,SAAS;AAC1C,aAAO,CAAC;AAAA,IACV;AAEA,WAAO,OAAO,WAAW,IAAI,CAAC,WAAW,OAAO;AAAA,MAC9C,WAAW,UAAU,QAAQ;AAAA,MAC7B,OAAO,OAAO,SAAS,CAAC,KAAK;AAAA,IAC/B,EAAE;AAAA,EACJ;AAGA,MAAI,QAAqD,CAAC;AAC1D,MAAI,SAAsD,CAAC;AAE3D,MAAI,WAAW;AACb,QAAI;AACF,YAAM,EAAE,sBAAAC,sBAAqB,IAAI,MAAM;AACvC,YAAM,gBAAgB,MAAMA;AAAA,QAC1B;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,cAAQ,cAAc;AACtB,eAAS,cAAc;AAAA,IACzB,SAAS,OAAO;AACd,cAAQ,MAAM,oCAAoC,KAAK;AAAA,IAEzD;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,YAAY,OAAO;AAAA,IAC1B,SAAS,YAAY,SAAS;AAAA,IAC9B,YAAY,YAAY,YAAY;AAAA,IACpC,YAAY,YAAY,YAAY;AAAA,IACpC;AAAA,IACA;AAAA,EACF;AACF;;;AD7HO,SAAS,oBAAoBC,SAA8B;AAChE,QAAM,SAASC,cAAa;AAK5B,SAAO,IAAI,WAAW,OAAO,KAAc,QAAkB;AAE3D,QAAI,UAAU,gBAAgB,mBAAmB;AACjD,QAAI,UAAU,iBAAiB,UAAU;AACzC,QAAI,UAAU,cAAc,YAAY;AAGxC,QAAI,MAAM,gCAAgC;AAG1C,UAAM,EAAE,WAAW,QAAQ,IAAI,IAAI;AACnC,UAAM,eAAe,OAAO;AAAA,MAC1B,OAAO,YACH,IAAI,KAAK,OAAO,SAAS,WAAqB,EAAE,CAAC,IACjD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAI;AAAA,MAC7C,KAAK,UACD,IAAI,KAAK,OAAO,SAAS,SAAmB,EAAE,CAAC,IAC/C,oBAAI,KAAK;AAAA,IACf;AAGA,UAAM,cAAc,YAAY;AAC9B,UAAI;AACF,gBAAQ,IAAI,8BAA8B;AAE1C,cAAM,YAAY,aAAa;AAE/B,gBAAQ,IAAI,eAAe,SAAS;AACpC,gBAAQ,IAAI,WAAW;AAAA,UACrB,QAAQD,QAAO;AAAA,UACf,SAASA,QAAO,UACZ,GAAGA,QAAO,QAAQ,UAAU,GAAG,EAAE,CAAC,QAClC;AAAA,QACN,CAAC;AAED,cAAM,CAAC,SAAS,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,UACzC;AAAA,YACEA,QAAO;AAAA,YACPA,QAAO;AAAA,YACP;AAAA,YACAA,QAAO;AAAA,UACT;AAAA,UACA,eAAeA,QAAO,SAASA,QAAO,MAAM;AAAA,QAC9C,CAAC;AAED,gBAAQ,IAAI,8BAA8B;AAE1C,cAAM,OAAO;AAAA,UACX,MAAM;AAAA,UACN,WAAW,KAAK,IAAI;AAAA,UACpB;AAAA,UACA;AAAA,QACF;AAEA,YAAI,MAAM,SAAS,KAAK,UAAU,IAAI,CAAC;AAAA;AAAA,CAAM;AAAA,MAC/C,SAAS,OAAgB;AACvB,cAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,gBAAQ,MAAM,2BAA2B,KAAK;AAC9C,YAAI;AAAA,UACF,SAAS,KAAK,UAAU,EAAE,MAAM,SAAS,OAAO,aAAa,CAAC,CAAC;AAAA;AAAA;AAAA,QACjE;AAAA,MACF;AAAA,IACF;AAGA,UAAM,YAAY;AAGlB,UAAM,WAAW,YAAY,aAAa,GAAM;AAGhD,QAAI,GAAG,SAAS,MAAM;AACpB,oBAAc,QAAQ;AAAA,IACxB,CAAC;AAAA,EACH,CAAC;AAKD,SAAO,IAAI,aAAa,OAAO,MAAe,QAAkB;AAC9D,QAAI;AACF,YAAM,YAAY;AAAA,QAChB,OAAO,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAI;AAAA,QAChD,KAAK,oBAAI,KAAK;AAAA,MAChB;AAEA,YAAM,CAAC,SAAS,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,QACzC;AAAA,UACEA,QAAO;AAAA,UACPA,QAAO;AAAA,UACP;AAAA,UACAA,QAAO;AAAA,QACT;AAAA,QACA,eAAeA,QAAO,SAASA,QAAO,MAAM;AAAA,MAC9C,CAAC;AAED,UAAI,KAAK,EAAE,SAAS,MAAM,CAAC;AAAA,IAC7B,SAAS,OAAgB;AACvB,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,IAC9C;AAAA,EACF,CAAC;AAKD,SAAO,IAAI,KAAK,OAAO,KAAc,QAAkB;AACrD,QAAI;AACF,YAAM,EAAE,WAAW,QAAQ,IAAI,IAAI;AAGnC,YAAM,YAAY;AAAA,QAChB,OAAO,YACH,IAAI,KAAK,OAAO,SAAS,WAAqB,EAAE,CAAC,IACjD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAI;AAAA,QAC7C,KAAK,UACD,IAAI,KAAK,OAAO,SAAS,SAAmB,EAAE,CAAC,IAC/C,oBAAI,KAAK;AAAA,MACf;AAEA,YAAM,CAAC,SAAS,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,QACzC;AAAA,UACEA,QAAO;AAAA,UACPA,QAAO;AAAA,UACP;AAAA,UACAA,QAAO;AAAA,QACT;AAAA,QACA,eAAeA,QAAO,SAASA,QAAO,MAAM;AAAA,MAC9C,CAAC;AAED,UAAI,KAAK;AAAA,QACP;AAAA,QACA;AAAA,QACA,WAAW,KAAK,IAAI;AAAA,MACtB,CAAC;AAAA,IACH,SAAS,OAAgB;AACvB,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,cAAQ,MAAM,2BAA2B,KAAK;AAC9C,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,IAC9C;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;AE9JA;AAAA,OAAO,SAAS;AAEhB,SAAS,UAAUE,qBAAoB;;;ACFvC;AAKA;AALA;AAAA,EACE;AAAA,EACA,2BAAAC;AAAA,EACA,eAAAC;AAAA,OACK;AA0DP,eAAsB,sBACpB,SACA,QACA,eACkC;AAClC,QAAM,cAAc,UAAU,MAAM,WAAW,SAAS,MAAM,IAAI;AAClE,QAAMC,SAAQ,IAAID,aAAY,EAAE,QAAQ,YAAY,CAAC;AAErD,QAAM,WAAW,MAAMC,OAAM;AAAA,IAC3B,IAAI,2BAA2B;AAAA,MAC7B,sBAAsB;AAAA,IACxB,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,iBAAiB,SAAS,kBACtB;AAAA,MACE,sBAAsB,SAAS,gBAAgB;AAAA,MAC/C,aAAa,SAAS,gBAAgB;AAAA,IAGxC,IACA;AAAA,IACJ,iBAAiB,SAAS,kBACtB;AAAA,MACE,WAAW,SAAS,gBAAgB;AAAA,MAGpC,iBAAiB,SAAS,gBAAgB;AAAA,IAC5C,IACA;AAAA,IACJ,mBAAmB,SAAS,oBACxB;AAAA,MACE,0BACE,SAAS,kBAAkB,4BAA4B;AAAA,MACzD,gBAAgB,SAAS,kBAAkB;AAAA,IAC7C,IACA;AAAA,IACJ,gBAAgB,SAAS,iBACrB;AAAA,MACE,gBAAgB,SAAS,eAAe,kBAAkB;AAAA,IAC5D,IACA;AAAA,IACJ,oBAAoB,SAAS,qBACzB;AAAA,MACE,mBAAmB,SAAS,mBAAmB;AAAA,IAGjD,IACA;AAAA,EACN;AACF;AAKA,eAAsB,mBACpB,SACA,QACA,cAC+B;AAC/B,QAAM,cAAc,UAAU,MAAM,WAAW,SAAS,MAAM,IAAI;AAClE,QAAMA,SAAQ,IAAID,aAAY,EAAE,QAAQ,YAAY,CAAC;AAErD,QAAM,WAAW,MAAMC,OAAM;AAAA,IAC3B,IAAIF,yBAAwB;AAAA,MAC1B,eAAe;AAAA,IACjB,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,cAAc,SAAS;AAAA,IACvB;AAAA,IACA,oBACE,SAAS;AAAA,IACX,gBAAgB,SAAS,iBACrB;AAAA,MACE,QAAQ,SAAS,eAAe;AAAA,MAKhC,QAAQ,SAAS,eAAe;AAAA,MAChC,gBAAgB,SAAS,eAAe,kBAAkB;AAAA,MAC1D,kBAAkB,SAAS,eACxB;AAAA,IAGL,IACA;AAAA,IACJ,oBAAoB,SAAS,qBACzB;AAAA,MACE,gBAAgB,SAAS,mBAAmB;AAAA,MAC5C,sBAAsB,SAAS,mBAC5B;AAAA,MAGH,qBAAqB,SAAS,mBAC3B;AAAA,IAGL,IACA;AAAA,IACJ,sBAAsB,SAAS;AAAA,IAC/B,0BAA0B,SAAS,4BAA4B;AAAA,IAC/D,MAAM,SAAS,MAAM;AAAA,MACnB,CAAC,KAAK,QAAQ;AACZ,YAAI,IAAI,KAAK;AACX,cAAI,IAAI,GAAG,IAAI,IAAI,SAAS;AAAA,QAC9B;AACA,eAAO;AAAA,MACT;AAAA,MACA,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAKA,eAAsB,mBACpB,SACA,QACA,eACA,QACwB;AACxB,QAAM,WAA0B,CAAC;AAEjC,MAAI,eAAe;AACjB,QAAI;AACF,eAAS,mBAAmB,MAAM;AAAA,QAChC;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,sCAAsC,KAAK;AAAA,IAC3D;AAAA,EACF;AAEA,MAAI,QAAQ;AACV,QAAI;AACF,eAAS,WAAW,MAAM,mBAAmB,SAAS,QAAQ,MAAM;AAAA,IACtE,SAAS,OAAO;AACd,cAAQ,MAAM,mCAAmC,KAAK;AAAA,IACxD;AAAA,EACF;AAEA,SAAO;AACT;;;AD7MO,SAAS,qBAAqBG,SAA8B;AACjE,QAAM,SAASC,cAAa;AAK5B,SAAO,IAAI,eAAe,OAAO,MAAe,QAAkB;AAChE,QAAI;AACF,UAAI,KAAK;AAAA,QACP,kBAAkBD,QAAO,oBAAoB;AAAA,QAC7C,YAAYA,QAAO;AAAA,QACnB,WAAWA,QAAO;AAAA,QAClB,QAAQA,QAAO;AAAA,MACjB,CAAC;AAAA,IACH,SAAS,OAAgB;AACvB,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,cAAQ,MAAM,qCAAqC,KAAK;AACxD,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,IAC9C;AAAA,EACF,CAAC;AAKD,SAAO,IAAI,KAAK,OAAO,MAAe,QAAkB;AACtD,QAAI;AAEF,YAAM,WAAW,MAAM;AAAA,QACrBA,QAAO,aAAa;AAAA,QACpBA,QAAO;AAAA,MACT;AAEA,UAAI,CAAC,UAAU;AACb,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UAC1B,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAGA,YAAM,gBAAgB;AACtB,YAAM,SAAS,SAAS,SAAS,OAAO,OAAO;AAG/C,YAAM,WAAW,MAAM;AAAA,QACrBA,QAAO;AAAA,QACPA,QAAO;AAAA,QACP;AAAA,QACA;AAAA,MACF;AAGA,UAAI,KAAK;AAAA,QACP,GAAG;AAAA,QACH,QAAQA,QAAO;AAAA,MACjB,CAAC;AAAA,IACH,SAAS,OAAgB;AACvB,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,cAAQ,MAAM,4BAA4B,KAAK;AAC/C,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,IAC9C;AAAA,EACF,CAAC;AAKD,SAAO,IAAI,2BAA2B,OAAO,KAAc,QAAkB;AAC3E,QAAI;AACF,YAAM,EAAE,QAAQ,eAAe,IAAI,IAAI;AAEvC,UAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,MACpE;AAEA,UAAI,CAAC,kBAAkB,OAAO,mBAAmB,UAAU;AACzD,eAAO,IACJ,OAAO,GAAG,EACV,KAAK,EAAE,OAAO,qCAAqC,CAAC;AAAA,MACzD;AAEA,cAAQ,IAAI,gCAAgC,MAAM,EAAE;AACpD,cAAQ,IAAI,6BAA6B,cAAc,EAAE;AAGzD,YAAM,UAAU,MAAM,IAAI,aAAa,MAAM;AAE7C,cAAQ,IAAI,iCAAiC,OAAO;AAGpD,YAAM,WAAW,QAAQ;AAAA,QAAK,CAAC,WAC7B,OAAO,YAAY,EAAE,SAAS,eAAe,YAAY,CAAC;AAAA,MAC5D;AAEA,cAAQ,IAAI,sBAAsB,QAAQ,EAAE;AAE5C,UAAI,KAAK;AAAA,QACP;AAAA,QACA,OAAO,WACH,SACA,yBAAyB,cAAc,YAAY,QAAQ,KAAK,IAAI,CAAC;AAAA,MAC3E,CAAC;AAAA,IACH,SAAS,OAAY;AACnB,cAAQ,MAAM,6CAA6C,KAAK;AAGhE,UAAI,MAAM,SAAS,aAAa,MAAM,SAAS,aAAa;AAC1D,eAAO,IAAI,KAAK;AAAA,UACd,UAAU;AAAA,UACV,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,UAAI,KAAK;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAKD,SAAO,IAAI,iBAAiB,OAAO,KAAc,QAAkB;AACjE,QAAI;AACF,YAAM,EAAE,OAAO,IAAI,IAAI;AAEvB,UAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,MACpE;AAEA,YAAM,cAAc,UAAU,MAAM;AAEpC,cAAQ,IAAI,gCAAgC,WAAW,EAAE;AAGzD,YAAM,UAAU,MAAM,IAAI,WAAW,WAAW;AAEhD,cAAQ,IAAI,+BAA+B,OAAO;AAIlD,YAAM,WAAW,QAAQ,KAAK,CAAC,WAAW;AACxC,cAAM,QAAQ,OAAO,KAAK,EAAE;AAC5B,eAAO,MAAM,WAAW,UAAU;AAAA,MACpC,CAAC;AAED,cAAQ,IAAI,4BAA4B,QAAQ,EAAE;AAElD,UAAI,KAAK;AAAA,QACP,UAAU;AAAA,QACV,OAAO,WAAW,SAAY;AAAA,MAChC,CAAC;AAAA,IACH,SAAS,OAAY;AACnB,cAAQ,MAAM,mCAAmC,KAAK;AAGtD,UAAI,MAAM,SAAS,aAAa,MAAM,SAAS,aAAa;AAC1D,eAAO,IAAI,KAAK;AAAA,UACd,UAAU;AAAA,UACV,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,UAAI,KAAK;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAKD,SAAO,IAAI,uBAAuB,OAAO,KAAc,QAAkB;AACvE,QAAI;AACF,YAAM,EAAE,QAAQ,IAAI,IAAI;AAExB,UAAI,OAAO,YAAY,WAAW;AAChC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,MACpE;AAGA,YAAM,WAAW,MAAM;AAAA,QACrBA,QAAO,aAAa;AAAA,QACpBA,QAAO;AAAA,MACT;AAEA,UAAI,CAAC,UAAU;AACb,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UAC1B,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,YAAM,gBAAgB;AAEtB,cAAQ;AAAA,QACN,2CAA2C,aAAa,KAAK,OAAO;AAAA,MACtE;AAGA,YAAM,EAAE,aAAAE,cAAa,yCAAyC,IAC5D,MAAM,OAAO,uBAAuB;AACtC,YAAM,EAAE,YAAAC,YAAW,IAAI,MAAM;AAE7B,YAAM,cAAcH,QAAO,UACvB,MAAMG,YAAWH,QAAO,SAASA,QAAO,MAAM,IAC9C;AACJ,YAAM,YAAY,IAAIE,aAAY,EAAE,QAAQF,QAAO,QAAQ,YAAY,CAAC;AAExE,YAAM,UAAU;AAAA,QACd,IAAI,yCAAyC;AAAA,UAC3C,sBAAsB;AAAA,UACtB,gBAAgB;AAAA,QAClB,CAAC;AAAA,MACH;AAEA,cAAQ,IAAI,iDAAiD;AAE7D,UAAI,KAAK,EAAE,SAAS,KAAK,CAAC;AAAA,IAC5B,SAAS,OAAgB;AACvB,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,cAAQ,MAAM,8CAA8C,KAAK;AACjE,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,IAC9C;AAAA,EACF,CAAC;AAKD,SAAO,IAAI,0BAA0B,OAAO,KAAc,QAAkB;AAC1E,QAAI;AACF,YAAM,EAAE,QAAQ,IAAI,IAAI;AAExB,UAAI,OAAO,YAAY,WAAW;AAChC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,MACpE;AAGA,YAAM,WAAW,MAAM;AAAA,QACrBA,QAAO,aAAa;AAAA,QACpBA,QAAO;AAAA,MACT;AAEA,UAAI,CAAC,UAAU;AACb,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UAC1B,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,YAAM,gBAAgB;AAEtB,cAAQ;AAAA,QACN,8CAA8C,aAAa,KAAK,OAAO;AAAA,MACzE;AAGA,YAAM,EAAE,aAAAE,cAAa,4CAA4C,IAC/D,MAAM,OAAO,uBAAuB;AACtC,YAAM,EAAE,YAAAC,YAAW,IAAI,MAAM;AAE7B,YAAM,cAAcH,QAAO,UACvB,MAAMG,YAAWH,QAAO,SAASA,QAAO,MAAM,IAC9C;AACJ,YAAM,YAAY,IAAIE,aAAY,EAAE,QAAQF,QAAO,QAAQ,YAAY,CAAC;AAExE,YAAM,UAAU;AAAA,QACd,IAAI,4CAA4C;AAAA,UAC9C,sBAAsB;AAAA,UACtB,0BAA0B;AAAA,QAC5B,CAAC;AAAA,MACH;AAEA,cAAQ,IAAI,oDAAoD;AAEhE,UAAI,KAAK,EAAE,SAAS,KAAK,CAAC;AAAA,IAC5B,SAAS,OAAgB;AACvB,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,cAAQ,MAAM,iDAAiD,KAAK;AACpE,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,IAC9C;AAAA,EACF,CAAC;AAKD,SAAO;AAAA,IACL;AAAA,IACA,OAAO,KAAc,QAAkB;AACrC,UAAI;AACF,cAAM,EAAE,OAAO,IAAI,IAAI;AAEvB,YAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,iBAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,0BAA0B,CAAC;AAAA,QAClE;AAGA,cAAM,cAAc;AACpB,YAAI,CAAC,YAAY,KAAK,MAAM,GAAG;AAC7B,iBAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,wBAAwB,CAAC;AAAA,QAChE;AAGA,cAAM,WAAW,MAAM;AAAA,UACrBA,QAAO,aAAa;AAAA,UACpBA,QAAO;AAAA,QACT;AAEA,YAAI,CAAC,UAAU;AACb,iBAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,YAC1B,OAAO;AAAA,UACT,CAAC;AAAA,QACH;AAEA,cAAM,gBAAgB;AAEtB,gBAAQ;AAAA,UACN,2CAA2C,aAAa,KAAK,MAAM;AAAA,QACrE;AAGA,cAAM,EAAE,aAAAE,cAAa,0CAA0C,IAC7D,MAAM,OAAO,uBAAuB;AACtC,cAAM,EAAE,YAAAC,YAAW,IAAI,MAAM;AAI7B,cAAM,cAAcH,QAAO,UACvB,MAAMG,YAAWH,QAAO,SAASA,QAAO,MAAM,IAC9C;AACJ,cAAM,YAAY,IAAIE,aAAY;AAAA,UAChC,QAAQF,QAAO;AAAA,UACf;AAAA,QACF,CAAC;AAED,cAAM,UAAU;AAAA,UACd,IAAI,0CAA0C;AAAA,YAC5C,sBAAsB;AAAA,YACtB,sBAAsB;AAAA,UACxB,CAAC;AAAA,QACH;AAEA,gBAAQ,IAAI,iDAAiD;AAE7D,YAAI,KAAK,EAAE,SAAS,KAAK,CAAC;AAAA,MAC5B,SAAS,OAAgB;AACvB,cAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,gBAAQ,MAAM,8CAA8C,KAAK;AACjE,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AEhXA;AACA,SAAS,UAAUI,qBAAoB;AAIhC,SAAS,iBAAiBC,SAA8B;AAC7D,QAAM,SAASC,cAAa;AAK5B,SAAO,IAAI,KAAK,OAAO,MAAe,QAAkB;AACtD,QAAI;AACF,YAAM,YAAYD,QAAO,aAAa;AACtC,YAAM,SAASA,QAAO;AAEtB,cAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAGA,YAAM,WAAW,MAAM,uBAAuB,WAAW,MAAM;AAC/D,cAAQ;AAAA,QACN;AAAA,QACA,WAAW,UAAU;AAAA,MACvB;AAGA,UAAI,eAAe;AACnB,UAAI;AACF,YAAIA,QAAO,SAAS;AAClB,kBAAQ,IAAI,sDAAsD;AAClE,gBAAM,EAAE,YAAAE,YAAW,IAAI,MAAM;AAG7B,gBAAM,EAAE,WAAAC,YAAW,0BAA0B,IAAI,MAAM,OACrD,qBACF;AAEA,gBAAM,cAAc,MAAMD,YAAWF,QAAO,SAAS,MAAM;AAC3D,gBAAM,YAAY,IAAIG,WAAU,EAAE,QAAQ,YAAY,CAAC;AAEvD,gBAAM,WAAW,MAAM,UAAU;AAAA,YAC/B,IAAI,0BAA0B,CAAC,CAAC;AAAA,UAClC;AAEA,cAAI,SAAS,kBAAkB,SAAS,eAAe,SAAS,GAAG;AACjE,2BAAe,SAAS,eAAe,CAAC;AACxC,oBAAQ,IAAI,mCAAmC,YAAY;AAAA,UAC7D,OAAO;AACL,oBAAQ,IAAI,qDAAqD;AAAA,UACnE;AAAA,QACF,OAAO;AACL,kBAAQ,IAAI,sDAAsD;AAAA,QACpE;AAAA,MACF,SAAS,OAAO;AAEd,gBAAQ,MAAM,4CAA4C,KAAK;AAAA,MACjE;AAEA,YAAM,eAAe;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU,UAAU,YAAY;AAAA,QAChC,QAAQ,UAAU,UAAU,OAAO,QAAQ,UAAU;AAAA,QACrD,QAAQ,UAAU,UAAU,OAAO,UAAU;AAAA,QAC7C,WAAW,UAAU,aAAa;AAAA,MACpC;AAEA,cAAQ,IAAI,gCAAgC,YAAY;AACxD,UAAI,KAAK,YAAY;AAAA,IACvB,SAAS,OAAgB;AACvB,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,cAAQ,MAAM,wCAAwC,KAAK;AAC3D,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,IAC9C;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;AXvEA,IAAMC,aAAYC,MAAK,QAAQC,eAAc,YAAY,GAAG,CAAC;AAqB7D,eAAsB,mBACpBC,SACqB;AACrB,QAAM,MAAM,QAAQ;AAGpB,QAAM,YAAY,OAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AAGvD,MAAI,IAAI,QAAQ,KAAK,CAAC;AAKtB,QAAM,gBAAgB,oBAAI,IAAkD;AAC5E,QAAM,oBAAoB,KAAK;AAC/B,QAAM,0BAA0B;AAEhC,MAAI,IAAI,CAAC,KAAK,KAAK,SAAS;AAC1B,UAAM,KAAK,IAAI,MAAM,IAAI,OAAO,iBAAiB;AACjD,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,SAAS,cAAc,IAAI,EAAE;AAEnC,QAAI,CAAC,UAAU,MAAM,OAAO,WAAW;AAErC,oBAAc,IAAI,IAAI,EAAE,OAAO,GAAG,WAAW,MAAM,kBAAkB,CAAC;AACtE,WAAK;AAAA,IACP,WAAW,OAAO,QAAQ,yBAAyB;AAEjD,aAAO;AACP,WAAK;AAAA,IACP,OAAO;AAEL,UAAI,OAAO,GAAG,EAAE,KAAK;AAAA,QACnB,OAAO;AAAA,QACP,YAAY,KAAK,MAAM,OAAO,YAAY,OAAO,GAAI;AAAA,MACvD,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAGD,MAAI,IAAI,CAAC,MAAM,KAAK,SAAS;AAC3B,QAAI,UAAU,mBAAmB,MAAM;AACvC,QAAI,UAAU,0BAA0B,SAAS;AACjD,QAAI;AAAA,MACF;AAAA,MACA;AAAA,IAIF;AACA,SAAK;AAAA,EACP,CAAC;AAGD,MAAI,IAAI,CAAC,KAAK,MAAM,SAAS;AAC3B,YAAQ,IAAI,KAAI,oBAAI,KAAK,GAAE,YAAY,CAAC,KAAK,IAAI,MAAM,IAAI,IAAI,GAAG,EAAE;AACpE,SAAK;AAAA,EACP,CAAC;AAGD,MAAI;AAAA,IACF;AAAA,IACA,kBAAkB,SAAS;AAAA,IAC3B,oBAAoBA,OAAM;AAAA,EAC5B;AACA,MAAI;AAAA,IACF;AAAA,IACA,kBAAkB,SAAS;AAAA,IAC3B,oBAAoBA,OAAM;AAAA,EAC5B;AACA,MAAI;AAAA,IACF;AAAA,IACA,kBAAkB,SAAS;AAAA,IAC3B,mBAAmBA,OAAM;AAAA,EAC3B;AACA,MAAI;AAAA,IACF;AAAA,IACA,kBAAkB,SAAS;AAAA,IAC3B,qBAAqBA,OAAM;AAAA,EAC7B;AACA,MAAI,IAAI,aAAa,kBAAkB,SAAS,GAAG,iBAAiBA,OAAM,CAAC;AAI3E,QAAM,YAAYF,MAAK,KAAKD,YAAW,SAAS;AAChD,MAAI,IAAI,QAAQ,OAAO,SAAS,CAAC;AAGjC,MAAI,IAAI,KAAK,CAAC,MAAM,QAAQ;AAC1B,QAAI,SAASC,MAAK,KAAK,WAAW,YAAY,CAAC;AAAA,EACjD,CAAC;AAGD,MAAI,IAAI,YAAY;AAGpB,QAAM,SAAS,IAAI,OAAOE,QAAO,MAAM,WAAW;AAGlD,QAAM,iBAAiB,qBAAqB,EAAE,OAAO,CAAC;AAEtD,UAAQ,GAAG,WAAW,YAAY;AAChC,YAAQ,IAAI,gCAAgC;AAC5C,UAAM,eAAe,UAAU;AAC/B,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AAED,UAAQ,GAAG,UAAU,YAAY;AAC/B,YAAQ,IAAI,gCAAgC;AAC5C,UAAM,eAAe,UAAU;AAC/B,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AAED,QAAM,MAAM,oBAAoBA,QAAO,IAAI,UAAU,SAAS;AAE9D,SAAO,EAAE,KAAK,OAAO,UAAU;AACjC;;;ADjJA;AAEA;AAaA,eAAsB,UAAU,SAA0C;AACxE,EAAM,cAAMC,KAAG,KAAK,iBAAiB,CAAC;AAEtC,QAAM,WAAW,IAAI,mBAAmB;AAGxC,QAAM,WAAW,MAAM,SAAS;AAAA,IAC9B;AAAA,IACA,YAAY,uBAAuB;AAAA,EACrC;AAGA,QAAM,SAAS,MAAM,aAAa;AAGlC,MAAI,eAAoB,CAAC;AACzB,MAAI;AAEF,UAAM,oBAAoB;AAE1B,UAAM,QAAQ,MAAa,oBAAW,eAAe,YAAY;AAAA,MAC/D,WAAW,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,MAChD,SAAS,iBAAiB;AAAA,IAC5B,CAAC;AAED,mBAAe,MAAM,MAAM,QAAQ;AAAA,EACrC,SAAS,QAAiB;AACxB,aAAS,KAAK;AACd,IAAM,YAAI,MAAM,+BAA+B;AAC/C,YAAQ;AAAA,MACN,UAAUA,KAAG,KAAK,kBAAkB,CAAC;AAAA,IACvC;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,YAAY,aAAa,WAAW;AAC1C,QAAM,aAAa,aAAa,YAAY;AAC5C,QAAM,mBAAmB,aAAa,kBAAkB,SAAS;AAGjE,QAAM,OACJ,QAAQ,QAAS,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,MAAM,MAAM,MAAM,IAAI,EAAE,CAAC;AAGzE,WAAS,KAAK;AACd,EAAM,YAAI,QAAQ,8BAA8B;AAChD,UAAQ;AAAA,IACN,GAAGA,KAAG,IAAI,oDAAoD,CAAC;AAAA,EACjE;AAEA,QAAM,EAAE,IAAI,IAAI,MAAM,mBAAmB;AAAA,IACvC;AAAA,IACA,SAAS;AAAA;AAAA,IACT;AAAA,IACA;AAAA,IACA,WAAW,SAAS;AAAA,IACpB,QAAQ,QAAQ,UAAU;AAAA,IAC1B;AAAA,IACA;AAAA,EACF,CAAC;AAED,UAAQ,IAAI,MAAMA,KAAG,KAAK,YAAY,CAAC,IAAIA,KAAG,KAAK,GAAG,CAAC,EAAE;AACzD,UAAQ,IAAI,GAAGA,KAAG,IAAI,sBAAsB,CAAC,KAAK;AAGlD,MAAI,CAAC,QAAQ,QAAQ;AACnB,UAAM,KAAK,GAAG;AAAA,EAChB;AAGA,eAAa,WAAW;AAAA,IACtB,SAAS;AAAA,IACT;AAAA,IACA,SAAS,QAAQ,UAAU;AAAA,EAC7B,CAAC;AAGD,QAAM,IAAI,QAAQ,MAAM;AAAA,EAAC,CAAC;AAC5B;;;AapGA;AAGA;AAHA,YAAYC,aAAW;AACvB,OAAOC,UAAQ;AAYf,eAAsB,QAAQ,SAAwC;AACpE,EAAM,cAAMC,KAAG,KAAK,+BAA+B,CAAC;AAGpD,QAAMC,WAAgB,gBAAQ;AAC9B,EAAAA,SAAQ,MAAM,4BAA4B;AAE1C,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,uBAAuB;AACxC,IAAAA,SAAQ,KAAK,2BAA2B;AAAA,EAC1C,SAAS,OAAY;AACnB,IAAAA,SAAQ,KAAK,mCAAmC;AAChD,UAAM;AAAA,EACR;AAGA,QAAM,SAAS,MAAM,aAAa;AAGlC,QAAM,WAAW,MAAM,uBAAuB,SAAS,WAAW,MAAM;AAExE,QAAM,mBAA6B,CAAC;AAEpC,MAAI,UAAU,UAAU,OAAO;AAC7B,qBAAiB,KAAK,OAAO;AAAA,EAC/B;AAEA,MAAI,iBAAiB,WAAW,GAAG;AACjC,IAAM,YAAI,KAAK,wCAAwC;AACvD,YAAQ;AAAA,MACN;AAAA,MAASD,KAAG,KAAK,kBAAkB,CAAC;AAAA;AAAA,IACtC;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,MAAI,iBAAiB,WAAW,GAAG;AACjC,UAAM,UAAU,iBAAiB,CAAC;AAClC,IAAM,YAAI,KAAK,SAASA,KAAG,KAAK,OAAO,CAAC,mBAAmB;AAE3D,QAAI,YAAY,SAAS;AAEvB,YAAM,aAAa,OAAO;AAC1B;AAAA,IACF;AAAA,EACF;AAGA,QAAM,mBAAmB,MAAY,eAAO;AAAA,IAC1C,SAAS;AAAA,IACT,SAAS;AAAA,MACP,GAAG,iBAAiB,IAAI,CAAC,OAAO;AAAA,QAC9B,OAAO;AAAA,QACP,OAAO,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC;AAAA,QAC5C,MAAM,MAAM,UAAU,iCAAiC;AAAA,MACzD,EAAE;AAAA,MACF;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAU,iBAAS,gBAAgB,GAAG;AACpC,IAAM,eAAO,sBAAsB;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,MAAI,qBAAqB,WAAW,qBAAqB,OAAO;AAC9D,QAAI,iBAAiB,SAAS,OAAO,GAAG;AACtC,YAAM,aAAa,OAAO;AAAA,IAC5B;AAAA,EACF;AAEA,MAAI,qBAAqB,OAAO;AAC9B,IAAM,cAAMA,KAAG,MAAM,2CAA2C,CAAC;AAAA,EACnE;AACF;;;AC7FA;AAGA;AAEA;AALA,YAAYE,aAAW;AACvB,YAAYC,cAAY;AACxB,OAAOC,UAAQ;AAgBf,eAAsB,OAAO,UAAwC;AACnE,QAAM,YAAY,KAAK,IAAI;AAC3B,QAAM,WAAW,IAAI,mBAAmB;AAExC,EAAM,cAAMC,KAAG,KAAK,6BAA6B,CAAC;AAGlD,QAAM,WAAW,MAAM,SAAS;AAAA,IAC9B;AAAA,IACA,YAAY,uBAAuB;AAAA,EACrC;AAEA,WAAS,KAAK,gBAAgBA,KAAG,KAAK,SAAS,SAAS,CAAC,EAAE;AAG3D,QAAM,SAAS,MAAM,aAAa;AAClC,WAAS,KAAK,WAAWA,KAAG,KAAK,MAAM,CAAC,EAAE;AAG1C,QAAM,WAID,CAAC;AAGN,MAAI;AACF,UAAM,oBAAoB;AAC1B,UAAM,QAAQ,MAAa,oBAAW,eAAe,YAAY;AAAA,MAC/D,WAAW,SAAS,SAAS,SAAS,IAAI,MAAM;AAAA,MAChD,SAAS,iBAAiB;AAAA,IAC5B,CAAC;AACD,UAAM,UAAU,MAAM,MAAM,QAAQ;AAEpC,QAAI,QAAQ,SAAS,OAAO;AAC1B,YAAM,cAAc,QAAQ,SAAS,OAAO,UAAU;AACtD,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS,cAAc,IAAI,GAAG,WAAW,eAAe;AAAA,MAC1D,CAAC;AAAA,IACH,OAAO;AACL,eAAS,KAAK,EAAE,MAAM,SAAS,QAAQ,eAAe,CAAC;AAAA,IACzD;AAAA,EACF,SAAS,QAAQ;AACf,aAAS,KAAK,EAAE,MAAM,SAAS,QAAQ,eAAe,CAAC;AAAA,EACzD;AAEA,WAAS,KAAK;AAGd,UAAQ,IAAI;AACZ,EAAM;AAAA,IACJ,SACG,IAAI,CAAC,MAAM;AACV,UAAI,EAAE,WAAW,YAAY;AAC3B,cAAM,UAAU,EAAE,UAAUA,KAAG,IAAI,KAAK,EAAE,OAAO,GAAG,IAAI;AACxD,eAAO,KAAKA,KAAG,MAAM,QAAG,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO;AAAA,MAC/C;AACA,aAAO,KAAKA,KAAG,IAAI,QAAG,CAAC,IAAI,EAAE,IAAI,IAAIA,KAAG,IAAI,gBAAgB,CAAC;AAAA,IAC/D,CAAC,EACA,KAAK,IAAI;AAAA,IACZ;AAAA,EACF;AAGA,QAAM,sBAAsB,SAAS,KAAK,CAAC,MAAM,EAAE,WAAW,UAAU;AAExE,MAAI,qBAAqB;AACvB,YAAQ,IAAI;AAAA,EAAKA,KAAG,KAAK,UAAU,CAAC,EAAE;AACtC,QAAI,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,GAAG,WAAW,YAAY;AACnE,cAAQ;AAAA,QACN,KAAKA,KAAG,IAAI,QAAQ,CAAC,IAAIA,KAAG,KAAK,oBAAoB,CAAC;AAAA,MACxD;AAAA,IACF;AAAA,EACF,OAAO;AACL,YAAQ,IAAI;AAAA,EAAKA,KAAG,KAAK,cAAc,CAAC,EAAE;AAC1C,YAAQ;AAAA,MACN,KAAKA,KAAG,IAAI,eAAe,CAAC,IAAIA,KAAG,KAAK,kBAAkB,CAAC;AAAA,IAC7D;AAAA,EACF;AAEA,UAAQ,IAAI;AAAA,EAAKA,KAAG,KAAK,YAAY,CAAC,IAAIA,KAAG,KAAK,uBAAuB,CAAC,EAAE;AAC5E,UAAQ,IAAI,GAAGA,KAAG,KAAK,OAAO,CAAC,IAAIA,KAAG,KAAK,wBAAwB,CAAC;AAAA,CAAI;AAGxE,eAAa,UAAU;AAAA,IACrB,SAAS;AAAA,IACT,mBAAmB,SAAS,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,EAAE;AAAA,IACnE,aAAa,KAAK,IAAI,IAAI;AAAA,EAC5B,CAAC;AACH;;;AC7GA;AAOA;AAFA,YAAYC,aAAW;AACvB,OAAOC,UAAQ;AAMf,eAAsB,kBAAiC;AACrD,QAAM,SAAS,mBAAmB;AAElC,SAAO,OAAO;AAEd,EAAM,YAAI,QAAQA,KAAG,MAAM,mBAAmB,CAAC;AAC/C,UAAQ,IAAI,cAAcA,KAAG,IAAI,OAAO,cAAc,CAAC,CAAC,EAAE;AAC1D,UAAQ,IAAI;AAAA,KAAQA,KAAG,IAAI,sCAAsC,CAAC;AAAA,CAAI;AACxE;AAKA,eAAsB,mBAAkC;AACtD,QAAM,SAAS,mBAAmB;AAElC,SAAO,QAAQ;AAEf,EAAM,YAAI,QAAQA,KAAG,MAAM,oBAAoB,CAAC;AAChD,UAAQ,IAAI,cAAcA,KAAG,IAAI,OAAO,cAAc,CAAC,CAAC,EAAE;AAC1D,UAAQ;AAAA,IACN;AAAA,KAAQA,KAAG,IAAI,yBAAyB,CAAC;AAAA;AAAA,EAC3C;AACF;AAKA,eAAsB,kBAAiC;AACrD,QAAM,SAAS,mBAAmB;AAElC,EAAM,cAAMA,KAAG,KAAK,kBAAkB,CAAC;AAEvC,QAAMC,UAAS,OAAO,UAAU,IAAID,KAAG,MAAM,SAAS,IAAIA,KAAG,IAAI,UAAU;AAE3E,UAAQ,IAAI;AACZ,UAAQ,IAAI,KAAKA,KAAG,KAAK,SAAS,CAAC,IAAIC,OAAM,EAAE;AAC/C,UAAQ,IAAI,KAAKD,KAAG,KAAK,cAAc,CAAC,IAAIA,KAAG,IAAI,OAAO,cAAc,CAAC,CAAC,EAAE;AAG5E,MAAI,OAAO,UAAU,GAAG;AACtB,YAAQ,IAAI;AACZ,YAAQ,IAAIA,KAAG,KAAK,mBAAmB,CAAC;AACxC,YAAQ,IAAI,OAAOA,KAAG,KAAK,yBAAyB,CAAC,EAAE;AACvD,YAAQ;AAAA,MACN,OAAOA,KAAG,IAAI,SAAS,CAAC,IAAIA,KAAG,KAAK,4BAA4B,CAAC;AAAA,IACnE;AACA,YAAQ,IAAI,OAAOA,KAAG,IAAI,SAAS,CAAC,IAAIA,KAAG,KAAK,gBAAgB,CAAC,EAAE;AAAA,EACrE,OAAO;AACL,YAAQ,IAAI;AACZ,YAAQ,IAAIA,KAAG,KAAK,kBAAkB,CAAC;AACvC,YAAQ,IAAI,OAAOA,KAAG,KAAK,wBAAwB,CAAC,EAAE;AAAA,EACxD;AAGA,UAAQ,IAAI;AACZ,UAAQ,IAAIA,KAAG,KAAK,eAAe,CAAC;AACpC,UAAQ;AAAA,IACN,OAAOA,KAAG,IAAI,yBAAyB,CAAC,IAAIA,KAAG,KAAK,yCAAyC,CAAC;AAAA,EAChG;AAGA,UAAQ,IAAI;AACZ,UAAQ;AAAA,IACN,KAAKA,KAAG,IAAI,aAAa,CAAC,IAAIA,KAAG,KAAK,kCAAkC,CAAC;AAAA,EAC3E;AACA,UAAQ,IAAI;AACd;;;AvC7CA;AACA;;;AwCnCA;AAMO,SAAS,qBAAqB;AAGrC;AAKO,SAAS,wBAAwB;AACtC,UAAQ,IAAI,4BAA4B;AACxC,UAAQ,IAAI,8BAA8B;AAC1C,UAAQ,IAAI,2DAA2D;AACvE,UAAQ,IAAI,+CAA+C;AAC3D,UAAQ,IAAI,mBAAmB;AAC/B,UAAQ;AAAA,IACN;AAAA,EACF;AACA,UAAQ,IAAI,6CAA6C;AACzD,UAAQ,IAAI,iDAAiD;AAC7D,UAAQ,IAAI,0CAA0C;AACtD,UAAQ,IAAI,sBAAsB;AAClC,UAAQ,IAAI,yBAAyB;AACrC,UAAQ,IAAI,uDAAuD;AACnE,UAAQ,IAAI,+CAA+C;AAC3D,UAAQ,IAAI,+CAA+C;AAC3D,UAAQ,IAAI,8BAA8B;AAC1C,UAAQ,IAAI,kDAAkD;AAC9D,UAAQ,IAAI,oDAAoD;AAChE,UAAQ,IAAI,8DAA8D;AAC1E,UAAQ,IAAI,oBAAoB;AAChC,UAAQ,IAAI,kBAAkB;AAC9B,UAAQ,IAAI,yCAAyC;AACrD,UAAQ,IAAI,+CAA+C;AAC3D,UAAQ,IAAI,sBAAsB;AAClC,UAAQ,IAAI,+CAA+C;AAC3D,UAAQ,IAAI,uBAAuB;AACnC,UAAQ,IAAI,iEAAiE;AAC7E,UAAQ,IAAI,UAAU;AACtB,UAAQ,IAAI,mDAAmD;AAC/D,UAAQ;AAAA,IACN;AAAA,EACF;AACA,UAAQ,IAAI,0DAA0D;AACtE,UAAQ,IAAI,+CAA+C;AAC3D,UAAQ,IAAI,+DAA+D;AAC3E,UAAQ,IAAI,iDAAiD;AAC7D,UAAQ,IAAI,oDAAoD;AAChE,UAAQ,IAAI,2DAA2D;AACzE;;;AxCdA;AAGA,IAAME,cAAaC,eAAc,YAAY,GAAG;AAChD,IAAMC,aAAYC,SAAQH,WAAU;AACpC,IAAM,cAAc,KAAK;AAAA,EACvB,aAAaI,MAAKF,YAAW,iBAAiB,GAAG,OAAO;AAC1D;AACA,IAAM,UAAU,YAAY;AAG5B,mBAAmB;AAGnB,SAAS,cAAc;AACrB,UAAQ,IAAI,UAAU,OAAO,EAAE;AAC/B,UAAQ,KAAK,CAAC;AAChB;AAGA,SAAS,WAAW;AAClB,EAAM,cAAMG,KAAG,KAAK,cAAc,OAAO,EAAE,CAAC;AAC5C,UAAQ,IAAI,6CAA6C;AACzD,UAAQ,IAAI,8CAA8C;AAC1D,UAAQ,IAAI,WAAW;AACvB,UAAQ,IAAI,KAAKA,KAAG,KAAK,OAAO,CAAC;AAAA,CAAyC;AAC1E,UAAQ,IAAI,iBAAiB;AAC7B,UAAQ;AAAA,IACN,KAAKA,KAAG,KAAK,YAAY,CAAC;AAAA,EAC5B;AACA,UAAQ;AAAA,IACN,KAAKA,KAAG,KAAK,eAAe,CAAC;AAAA,EAC/B;AACA,UAAQ,IAAI,KAAKA,KAAG,KAAK,cAAc,CAAC,4CAA4C;AACpF,UAAQ,IAAI,KAAKA,KAAG,KAAK,cAAc,CAAC,oCAAoC;AAC5E,UAAQ;AAAA,IACN,KAAKA,KAAG,KAAK,YAAY,CAAC;AAAA,EAC5B;AACA,UAAQ,IAAI,KAAKA,KAAG,KAAK,eAAe,CAAC,sBAAsB;AAC/D,UAAQ;AAAA,IACN,KAAKA,KAAG,KAAK,eAAe,CAAC;AAAA,EAC/B;AACA,UAAQ;AAAA,IACN,KAAKA,KAAG,KAAK,eAAe,CAAC;AAAA,EAC/B;AACA,UAAQ,IAAI,KAAKA,KAAG,KAAK,mBAAmB,CAAC,yBAAyB;AACtE,UAAQ,IAAI,KAAKA,KAAG,KAAK,oBAAoB,CAAC,qBAAqB;AACnE,UAAQ,IAAI,KAAKA,KAAG,KAAK,sBAAsB,CAAC;AAAA,CAAoB;AACpE,UAAQ,IAAI,sBAAsB;AAClC,UAAQ,IAAI,KAAKA,KAAG,KAAK,SAAS,CAAC,wCAAwC;AAC3E,UAAQ;AAAA,IACN,KAAKA,KAAG,KAAK,uBAAuB,CAAC;AAAA;AAAA,EACvC;AACA,UAAQ,IAAI,kBAAkB;AAC9B,UAAQ,IAAI,KAAKA,KAAG,KAAK,QAAQ,CAAC,sCAAsC;AACxE,UAAQ,IAAI,KAAKA,KAAG,KAAK,SAAS,CAAC,sCAAsC;AACzE,UAAQ,IAAI,KAAKA,KAAG,KAAK,YAAY,CAAC,qCAAqC;AAC3E,UAAQ;AAAA,IACN,KAAKA,KAAG,KAAK,WAAW,CAAC;AAAA;AAAA,EAC3B;AACA,UAAQ,IAAI,UAAU;AACtB,UAAQ;AAAA,IACN,KAAKA,KAAG,IAAI,gBAAgB,CAAC;AAAA,EAC/B;AACA,UAAQ,IAAI,KAAKA,KAAG,IAAI,cAAc,CAAC,gBAAgB;AACvD,UAAQ,IAAI,KAAKA,KAAG,IAAI,cAAc,CAAC,iBAAiB;AACxD,UAAQ,IAAI,KAAKA,KAAG,IAAI,WAAW,CAAC,iCAAiC;AACrE,UAAQ,IAAI,KAAKA,KAAG,IAAI,UAAU,CAAC,+BAA+B;AAClE,UAAQ,IAAI,KAAKA,KAAG,IAAI,WAAW,CAAC,mCAAmC;AACvE,UAAQ,IAAI,KAAKA,KAAG,IAAI,aAAa,CAAC,oCAAoC;AAC1E,UAAQ;AAAA,IACN,KAAKA,KAAG,IAAI,WAAW,CAAC;AAAA,EAC1B;AACA,UAAQ,IAAI,KAAKA,KAAG,IAAI,eAAe,CAAC;AAAA,CAA2B;AACnE,UAAQ;AAAA,IACN,OAAOA,KAAG,KAAK,kCAAkC,CAAC;AAAA;AAAA,EACpD;AACA,UAAQ,KAAK,CAAC;AAChB;AAGA,IAAI,QAAQ,KAAK,SAAS,WAAW,KAAK,QAAQ,KAAK,SAAS,IAAI,GAAG;AACrE,cAAY;AACd;AAGA,IAAI,QAAQ,KAAK,SAAS,QAAQ,KAAK,QAAQ,KAAK,SAAS,IAAI,GAAG;AAClE,WAAS;AACX;AAGA,KAAK,QAAQ;AAAA,EACX;AAAA,IACE,MAAM,CAAC,KAAK,UAAU;AAAA,IACtB,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,MAAM,CAAC,KAAK,QAAQ;AAAA,IACpB,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,MAAM,CAAC,KAAK,QAAQ;AAAA,IACpB,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,MAAM,CAAC,KAAK,KAAK;AAAA,IACjB,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,MAAM,CAAC,KAAK,OAAO;AAAA,IACnB,aACE;AAAA,IACF,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AACF,CAAC;AAGD,IAAM,QAAQ,KAAK,MAAM,QAAQ,IAAI;AACrC,IAAM,CAAC,gBAAgB,UAAU,IAAI,KAAK;AAG1C,IAAI,CAAC,gBAAgB;AACnB,iBAAe,gBAAgB;AAC7B,IAAM,cAAMA,KAAG,KAAK,cAAc,OAAO,EAAE,CAAC;AAC5C,YAAQ,IAAI,mEAAmE;AAG/E,UAAM,SAAS,MAAY,eAAO;AAAA,MAChC,SAAS;AAAA,MACT,SAAS;AAAA,QACP;AAAA,UACE,OAAO;AAAA,UACP,OAAO;AAAA,UACP,MAAM;AAAA,QACR;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,OAAO;AAAA,UACP,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF,CAAC;AAED,QAAU,iBAAS,MAAM,GAAG;AAC1B,MAAM,eAAO,sBAAsB;AACnC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAGA,QAAI,WAAW,QAAQ;AACrB,YAAM,KAAK;AAAA,QACT,UAAU,MAAM;AAAA,QAChB,QAAQ,MAAM;AAAA,QACd,QAAQ,MAAM;AAAA,QACd,QAAQ,MAAM;AAAA,QACd,KAAK,MAAM;AAAA,QACX,SAAS,MAAM;AAAA,MACjB,CAAC;AAAA,IACH,OAAO;AACL,YAAM,QAAQ;AAAA,QACZ,UAAU,MAAM;AAAA,QAChB,QAAQ,MAAM;AAAA,QACd,KAAK,MAAM;AAAA,QACX,SAAS,MAAM;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,gBAAc,EAAE,MAAM,cAAc;AAEpC,UAAQ,KAAK,CAAC;AAChB;AAGA,eAAe,MAAM;AACnB,QAAM,YAAY,KAAK,IAAI;AAC3B,QAAM,YAAY,mBAAmB;AAGrC,MAAI,UAAU,uBAAuB,GAAG;AACtC,YAAQ,IAAI;AACZ,IAAM,YAAI,KAAKA,KAAG,KAAK,qBAAqB,CAAC;AAC7C,YAAQ;AAAA,MACN,oBAAoBA,KAAG,KAAK,sBAAsB,CAAC;AAAA,IACrD;AACA,YAAQ;AAAA,MACN,QAAQA,KAAG,KAAK,OAAO,CAAC;AAAA,IAC1B;AACA,YAAQ;AAAA,MACN,QAAQA,KAAG,KAAK,MAAM,CAAC;AAAA,IACzB;AACA,YAAQ,IAAI;AACZ,YAAQ,IAAI,sBAAsBA,KAAG,KAAK,yBAAyB,CAAC,EAAE;AACtE,YAAQ,IAAI,aAAaA,KAAG,KAAK,4BAA4B,CAAC,EAAE;AAChE,YAAQ,IAAI,iBAAiBA,KAAG,KAAK,kCAAkC,CAAC,EAAE;AAC1E,YAAQ,IAAI;AAEZ,cAAU,sBAAsB;AAAA,EAClC;AAEA,MAAI;AAEF,QAAI,mBAAmB,WAAW,YAAY;AAC5C,cAAQ,YAAY;AAAA,QAClB,KAAK;AACH,gBAAM,KAAK;AAAA,YACT,UAAU,MAAM;AAAA,YAChB,QAAQ,MAAM;AAAA,YACd,QAAQ,MAAM;AAAA,YACd,QAAQ,MAAM;AAAA,YACd,KAAK,MAAM;AAAA,YACX,SAAS,MAAM;AAAA,UACjB,CAAC;AACD;AAAA,QAEF,KAAK;AACH,gBAAM,QAAQ;AAAA,YACZ,UAAU,MAAM;AAAA,YAChB,QAAQ,MAAM;AAAA,YACd,KAAK,MAAM;AAAA,YACX,SAAS,MAAM;AAAA,UACjB,CAAC;AACD;AAAA,QAEF,KAAK;AAAA,QACL,KAAK;AACH,gBAAM,OAAO;AAAA,YACX,QAAQ,MAAM;AAAA,YACd,KAAK,MAAM;AAAA,YACX,SAAS,MAAM;AAAA,UACjB,CAAC;AACD;AAAA,QAEF,KAAK;AACH,gBAAM,QAAQ;AAAA,YACZ,QAAQ,MAAM;AAAA,YACd,KAAK,MAAM;AAAA,YACX,SAAS,MAAM;AAAA,UACjB,CAAC;AACD;AAAA,QAEF,KAAK;AACH,gBAAM,QAAQ;AAAA,YACZ,QAAQ,MAAM;AAAA,YACd,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,UACjB,CAAC;AACD;AAAA,QAEF,KAAK;AACH,gBAAM,YAAY;AAAA,YAChB,SAAS,MAAM;AAAA,UACjB,CAAC;AACD;AAAA,QAEF,KAAK,UAAU;AACb,cAAI,CAAC,MAAM,QAAQ;AACjB,YAAM,YAAI,MAAM,2BAA2B;AAC3C,oBAAQ;AAAA,cACN;AAAA,SAAYA,KAAG,KAAK,yCAAyC,CAAC;AAAA;AAAA,YAChE;AACA,oBAAQ,KAAK,CAAC;AAAA,UAChB;AACA,gBAAM,aAAa,EAAE,QAAQ,MAAM,OAAO,CAAC;AAC3C;AAAA,QACF;AAAA,QAEA,KAAK,WAAW;AAEd,gBAAM,oBAAoB,KAAK,IAAI,CAAC;AAEpC,kBAAQ,mBAAmB;AAAA,YACzB,KAAK,OAAO;AACV,kBAAI,CAAC,MAAM,QAAQ;AACjB,gBAAM,YAAI,MAAM,2BAA2B;AAC3C,wBAAQ;AAAA,kBACN;AAAA,SAAYA,KAAG,KAAK,8CAA8C,CAAC;AAAA;AAAA,gBACrE;AACA,wBAAQ,KAAK,CAAC;AAAA,cAChB;AACA,oBAAM,UAAU,EAAE,QAAQ,MAAM,OAAO,CAAC;AACxC;AAAA,YACF;AAAA,YAEA,KAAK;AACH,oBAAM,YAAY;AAClB;AAAA,YAEF,KAAK,UAAU;AACb,kBAAI,CAAC,MAAM,QAAQ;AACjB,gBAAM,YAAI,MAAM,2BAA2B;AAC3C,wBAAQ;AAAA,kBACN;AAAA,SAAYA,KAAG,KAAK,iDAAiD,CAAC;AAAA;AAAA,gBACxE;AACA,wBAAQ,KAAK,CAAC;AAAA,cAChB;AACA,oBAAM,aAAa,EAAE,QAAQ,MAAM,OAAO,CAAC;AAC3C;AAAA,YACF;AAAA,YAEA,KAAK,YAAY;AACf,kBAAI,CAAC,MAAM,QAAQ;AACjB,gBAAM,YAAI,MAAM,2BAA2B;AAC3C,wBAAQ;AAAA,kBACN;AAAA,SAAYA,KAAG,KAAK,mDAAmD,CAAC;AAAA;AAAA,gBAC1E;AACA,wBAAQ,KAAK,CAAC;AAAA,cAChB;AACA,oBAAM,QAAQ,EAAE,QAAQ,MAAM,OAAO,CAAC;AACtC;AAAA,YACF;AAAA,YAEA,KAAK,UAAU;AACb,kBAAI,CAAC,MAAM,QAAQ;AACjB,gBAAM,YAAI,MAAM,2BAA2B;AAC3C,wBAAQ;AAAA,kBACN;AAAA,SAAYA,KAAG,KAAK,yDAAyD,CAAC;AAAA;AAAA,gBAChF;AACA,wBAAQ,KAAK,CAAC;AAAA,cAChB;AACA,oBAAM,aAAa;AAAA,gBACjB,QAAQ,MAAM;AAAA,gBACd,OAAO,MAAM;AAAA,cACf,CAAC;AACD;AAAA,YACF;AAAA,YAEA;AACE,cAAM,YAAI;AAAA,gBACR,4BAA4B,qBAAqB,QAAQ;AAAA,cAC3D;AACA,sBAAQ;AAAA,gBACN;AAAA,sBAAyBA,KAAG,KAAK,KAAK,CAAC,KAAKA,KAAG,KAAK,MAAM,CAAC,KAAKA,KAAG,KAAK,QAAQ,CAAC,KAAKA,KAAG,KAAK,UAAU,CAAC,KAAKA,KAAG,KAAK,QAAQ,CAAC;AAAA;AAAA,cACjI;AACA,sBAAQ,KAAK,CAAC;AAAA,UAClB;AACA;AAAA,QACF;AAAA,QAEA,KAAK;AACH,gBAAM,aAAa;AAAA,YACjB,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,UACjB,CAAC;AACD;AAAA,QAEF;AACE,UAAM,YAAI,MAAM,0BAA0B,UAAU,EAAE;AACtD,kBAAQ;AAAA,YACN;AAAA,MAASA,KAAG,KAAK,cAAc,CAAC;AAAA;AAAA,UAClC;AACA,kBAAQ,KAAK,CAAC;AAAA,MAClB;AAEA,YAAM,gBAAgB,KAAK,IAAI,IAAI;AACnC,YAAM,mBAAmB,SAAS,UAAU;AAC5C,mBAAa,kBAAkB;AAAA,QAC7B,SAAS;AAAA,QACT,aAAa;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAGA,QAAI,mBAAmB,eAAe,YAAY;AAChD,cAAQ,YAAY;AAAA,QAClB,KAAK;AACH,gBAAM,WAAW;AAAA,YACf,QAAQ,MAAM;AAAA,YACd,OAAO,MAAM;AAAA,UACf,CAAC;AACD;AAAA,QAEF;AACE,UAAM,YAAI,MAAM,8BAA8B,UAAU,EAAE;AAC1D,kBAAQ,IAAI;AAAA,sBAAyBA,KAAG,KAAK,aAAa,CAAC;AAAA,CAAI;AAC/D,kBAAQ,IAAI,OAAOA,KAAG,KAAK,cAAc,CAAC;AAAA,CAA0B;AACpE,kBAAQ,KAAK,CAAC;AAAA,MAClB;AAEA,YAAM,oBAAoB,KAAK,IAAI,IAAI;AACvC,YAAM,uBAAuB,aAAa,UAAU;AACpD,mBAAa,sBAAsB;AAAA,QACjC,SAAS;AAAA,QACT,aAAa;AAAA,MACf,CAAC;AACD;AAAA,IACF;AAGA,YAAQ,gBAAgB;AAAA;AAAA,MAEtB,KAAK;AACH,cAAM,OAAO;AAAA,UACX,SAAS,MAAM;AAAA,QACjB,CAAC;AACD;AAAA,MAEF,KAAK;AACH,cAAM,UAAU;AAAA,UACd,MAAM,MAAM;AAAA,UACZ,QAAQ,MAAM;AAAA,QAChB,CAAC;AACD;AAAA,MAEF,KAAK;AAEH,YAAI,CAAC,YAAY;AACf,UAAM,YAAI;AAAA,YACR,wCAAwCA,KAAG,KAAK,eAAe,CAAC;AAAA,UAClE;AACA,gBAAM,UAAU;AAAA,YACd,MAAM,MAAM;AAAA,YACZ,QAAQ,MAAM;AAAA,UAChB,CAAC;AAAA,QACH;AACA;AAAA,MAEF,KAAK;AACH,cAAM,QAAQ;AAAA,UACZ,OAAO,MAAM;AAAA,UACb,SAAS,MAAM;AAAA,QACjB,CAAC;AACD;AAAA,MAEF,KAAK;AACH,8BAAsB;AACtB;AAAA,MAEF,KAAK,aAAa;AAEhB,gBAAQ,YAAY;AAAA,UAClB,KAAK;AACH,kBAAM,gBAAgB;AACtB;AAAA,UAEF,KAAK;AACH,kBAAM,iBAAiB;AACvB;AAAA,UAEF,KAAK;AAAA,UACL,KAAK;AACH,kBAAM,gBAAgB;AACtB;AAAA,UAEF;AACE,YAAM,YAAI,MAAM,8BAA8B,UAAU,EAAE;AAC1D,oBAAQ;AAAA,cACN;AAAA,sBAAyBA,KAAG,KAAK,QAAQ,CAAC,KAAKA,KAAG,KAAK,SAAS,CAAC,KAAKA,KAAG,KAAK,QAAQ,CAAC;AAAA;AAAA,YACzF;AACA,oBAAQ,KAAK,CAAC;AAAA,QAClB;AACA;AAAA,MACF;AAAA;AAAA,MAGA,KAAK;AACH,gBAAQ;AAAA,UACN;AAAA,+BAAkC,cAAc;AAAA;AAAA,QAClD;AACA,iBAAS;AACT;AAAA,MAEF;AACE,QAAM,YAAI,MAAM,oBAAoB,cAAc,EAAE;AACpD,gBAAQ;AAAA,UACN;AAAA,MAASA,KAAG,KAAK,cAAc,CAAC;AAAA;AAAA,QAClC;AACA,gBAAQ,KAAK,CAAC;AAAA,IAClB;AAEA,UAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,UAAM,cAAc,aAChB,GAAG,cAAc,IAAI,UAAU,KAC/B;AAEJ,iBAAa,aAAa;AAAA,MACxB,SAAS;AAAA,MACT,aAAa;AAAA,IACf,CAAC;AAAA,EACH,SAAS,OAAO;AAEd,UAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,UAAM,cAAc,aAChB,GAAG,cAAc,IAAI,UAAU,KAC/B;AAEJ,iBAAa,aAAa;AAAA,MACxB,SAAS;AAAA,MACT,aAAa;AAAA,IACf,CAAC;AAED,mBAAe,KAAK;AAAA,EACtB,UAAE;AAEA,UAAM,UAAU,SAAS;AAAA,EAC3B;AACF;AAEA,IAAI;","names":["packageJson","acm","aws","config","aws","cloudfront","config","config","config","config","clack","pc","config","getAllPresetInfo","STSClient","MailManagerClient","DynamoDBClient","ScanCommand","unmarshall","dynamodb","dirname","join","fileURLToPath","clack","pc","intro","log","outro","pc","existsSync","join","join","existsSync","mkdir","clack","pc","status","intro","pc","log","iam","roleExists","outro","clack","pulumi","pc","aws","pulumi","DynamoDBClient","DescribeTableCommand","dynamodb","aws","config","aws","pulumi","IAMClient","GetRoleCommand","iam","config","existsSync","join","fileURLToPath","aws","pulumi","LambdaClient","lambda","config","aws","SESv2Client","GetConfigurationSetCommand","GetEmailIdentityCommand","config","aws","aws","IAMClient","iam","config","config","findHostedZone","createACMCertificate","createCloudFrontTracking","createMailManagerArchive","automation","installPulumiCli","pc","config","result","clack","pulumi","pc","IAMClient","GetIdentityVerificationAttributesCommand","ListIdentitiesCommand","SESClient","lambda","iam","pc","result","findHostedZone","createDNSRecords","clack","pulumi","pc","ChangeResourceRecordSetsCommand","ListHostedZonesByNameCommand","Route53Client","findHostedZone","Route53Client","ListHostedZonesByNameCommand","Route53Client","ChangeResourceRecordSetsCommand","SESv2Client","GetEmailIdentityCommand","pc","findHostedZone","SESv2Client","clack","pc","pc","SESv2Client","clack","pulumi","pc","pc","promptEmailArchiving","result","findHostedZone","createDNSRecords","clack","pulumi","pc","pc","clack","pulumi","pc","pc","SESv2Client","GetEmailIdentityCommand","identity","clack","pulumi","pc","pc","config","listSESDomains","findHostedZone","promptCustomConfig","result","createDNSRecords","clack","pulumi","pc","path","fileURLToPath","SESClient","GetEmailIdentityCommand","SESv2Client","sesv2","config","createRouter","DynamoDBClient","dynamodb","status","config","createRouter","fetchArchivedEmail","createRouter","cloudwatch","fetchDynamoDBMetrics","config","createRouter","createRouter","GetEmailIdentityCommand","SESv2Client","sesv2","config","createRouter","SESv2Client","assumeRole","createRouter","config","createRouter","assumeRole","IAMClient","__dirname","path","fileURLToPath","config","pc","clack","pc","pc","spinner","clack","pulumi","pc","pc","clack","pc","status","__filename","fileURLToPath","__dirname","dirname","join","pc"]}
1
+ {"version":3,"sources":["../../../node_modules/.pnpm/tsup@8.5.0_jiti@2.6.1_postcss@8.5.6_tsx@4.20.6_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js","../src/utils/shared/ci-detection.ts","../src/telemetry/config.ts","../package.json","../src/telemetry/client.ts","../src/telemetry/events.ts","../src/utils/shared/errors.ts","../src/utils/shared/aws.ts","../src/infrastructure/resources/lambda.ts","../src/utils/route53.ts","../src/infrastructure/resources/acm.ts","../src/infrastructure/resources/cloudfront.ts","../src/infrastructure/resources/mail-manager.ts","../src/utils/email/costs.ts","../src/utils/email/presets.ts","../src/utils/shared/prompts.ts","../src/utils/shared/assume-role.ts","../src/utils/archive.ts","../src/console/services/email-archive.ts","../src/console/services/dynamodb-metrics.ts","../src/cli.ts","../src/commands/dashboard/update-role.ts","../src/utils/shared/metadata.ts","../src/utils/shared/fs.ts","../src/utils/shared/output.ts","../src/commands/email/config.ts","../src/infrastructure/email-stack.ts","../src/infrastructure/resources/dynamodb.ts","../src/infrastructure/resources/eventbridge.ts","../src/infrastructure/resources/iam.ts","../src/infrastructure/resources/ses.ts","../src/infrastructure/resources/sqs.ts","../src/infrastructure/vercel-oidc.ts","../src/utils/shared/pulumi.ts","../src/commands/email/connect.ts","../src/utils/shared/scanner.ts","../src/commands/email/destroy.ts","../src/commands/email/domains.ts","../src/commands/email/init.ts","../src/commands/email/restore.ts","../src/commands/email/status.ts","../src/commands/email/upgrade.ts","../src/commands/shared/dashboard.ts","../src/console/server.ts","../src/console/middleware/auth.ts","../src/console/middleware/error.ts","../src/console/routes/domains.ts","../src/console/services/ses-service.ts","../src/console/routes/emails.ts","../src/console/services/email-logs.ts","../src/console/routes/metrics.ts","../src/console/services/aws-metrics.ts","../src/console/routes/settings.ts","../src/console/services/settings-service.ts","../src/console/routes/sms.ts","../src/console/services/sms-logs.ts","../src/console/services/sms-metrics.ts","../src/console/services/sms-settings.ts","../src/console/routes/user.ts","../src/commands/shared/destroy.ts","../src/commands/shared/status.ts","../src/commands/sms/destroy.ts","../src/infrastructure/sms-stack.ts","../src/commands/sms/init.ts","../src/utils/sms/costs.ts","../src/utils/sms/presets.ts","../src/commands/sms/register.ts","../src/commands/sms/status.ts","../src/commands/sms/sync.ts","../src/commands/sms/test.ts","../src/commands/sms/upgrade.ts","../src/commands/sms/verify-number.ts","../src/commands/telemetry.ts","../src/utils/shared/completion.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","/**\n * CI environment detection utilities\n * @module utils/shared/ci-detection\n */\n\n/**\n * Detect if running in CI environment\n *\n * Checks for common CI environment variables to determine\n * if the CLI is running in a continuous integration environment.\n *\n * @returns {boolean} True if running in CI, false otherwise\n *\n * @example\n * ```typescript\n * if (isCI()) {\n * console.log('Running in CI environment');\n * }\n * ```\n */\nexport function isCI(): boolean {\n // Universal CI indicator\n if (process.env.CI === \"true\" || process.env.CI === \"1\") {\n return true;\n }\n\n // Common CI providers\n const ciEnvVars = [\n \"GITHUB_ACTIONS\", // GitHub Actions\n \"GITLAB_CI\", // GitLab CI\n \"CIRCLECI\", // CircleCI\n \"TRAVIS\", // Travis CI\n \"JENKINS_URL\", // Jenkins\n \"BUILDKITE\", // Buildkite\n \"DRONE\", // Drone\n \"SEMAPHORE\", // Semaphore\n \"TEAMCITY_VERSION\", // TeamCity\n \"TF_BUILD\", // Azure Pipelines\n \"CODEBUILD_BUILD_ID\", // AWS CodeBuild\n \"NETLIFY\", // Netlify\n \"VERCEL\", // Vercel\n \"HEROKU_TEST_RUN_ID\", // Heroku CI\n \"BUDDY\", // Buddy\n \"BITBUCKET_BUILD_NUMBER\", // Bitbucket Pipelines\n ];\n\n return ciEnvVars.some((envVar) => process.env[envVar] !== undefined);\n}\n","/**\n * Telemetry configuration management\n * @module telemetry/config\n */\n\nimport Conf from \"conf\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport type { TelemetryConfig } from \"./types.js\";\n\nconst CONFIG_DEFAULTS: TelemetryConfig = {\n enabled: true,\n anonymousId: uuidv4(),\n notificationShown: false,\n};\n\nexport type TelemetryConfigOptions = {\n /** Custom config directory (for testing) */\n cwd?: string;\n};\n\n/**\n * Manages telemetry configuration stored locally\n *\n * Configuration is stored in platform-specific locations:\n * - macOS: ~/Library/Preferences/wraps/telemetry.json\n * - Linux: ~/.config/wraps/telemetry.json\n * - Windows: %APPDATA%\\wraps\\Config\\telemetry.json\n *\n * @example\n * ```typescript\n * const config = new TelemetryConfigManager();\n *\n * if (config.isEnabled()) {\n * console.log('Telemetry is enabled');\n * }\n *\n * config.setEnabled(false);\n * ```\n */\nexport class TelemetryConfigManager {\n private readonly config: Conf<TelemetryConfig>;\n\n constructor(options?: TelemetryConfigOptions) {\n this.config = new Conf<TelemetryConfig>({\n projectName: \"wraps\",\n configName: \"telemetry\",\n defaults: CONFIG_DEFAULTS,\n cwd: options?.cwd,\n });\n }\n\n /**\n * Check if telemetry is enabled\n */\n isEnabled(): boolean {\n return this.config.get(\"enabled\");\n }\n\n /**\n * Enable or disable telemetry\n */\n setEnabled(enabled: boolean): void {\n this.config.set(\"enabled\", enabled);\n }\n\n /**\n * Get the anonymous user ID\n */\n getAnonymousId(): string {\n return this.config.get(\"anonymousId\");\n }\n\n /**\n * Check if the first-run notification has been shown\n */\n hasShownNotification(): boolean {\n return this.config.get(\"notificationShown\");\n }\n\n /**\n * Mark the first-run notification as shown\n */\n markNotificationShown(): void {\n this.config.set(\"notificationShown\", true);\n }\n\n /**\n * Get the full path to the configuration file\n */\n getConfigPath(): string {\n return this.config.path;\n }\n\n /**\n * Reset configuration to defaults\n */\n reset(): void {\n this.config.clear();\n // Set new defaults with fresh UUID\n this.config.set({\n ...CONFIG_DEFAULTS,\n anonymousId: uuidv4(),\n });\n }\n}\n","{\n \"name\": \"@wraps.dev/cli\",\n \"version\": \"1.5.4\",\n \"description\": \"CLI for deploying Wraps email infrastructure to your AWS account\",\n \"type\": \"module\",\n \"main\": \"./dist/cli.js\",\n \"bin\": {\n \"wraps\": \"./dist/cli.js\"\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/wraps-team/wraps.git\",\n \"directory\": \"packages/cli\"\n },\n \"homepage\": \"https://wraps.dev\",\n \"bugs\": {\n \"url\": \"https://github.com/wraps-team/wraps/issues\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"dev\": \"tsup --watch\",\n \"build\": \"pnpm build:console && pnpm build:lambda && tsup\",\n \"build:lambda\": \"tsx scripts/build-lambda.ts\",\n \"build:console\": \"pnpm --filter @wraps/console build\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest --watch\",\n \"test:ui\": \"vitest --ui\",\n \"test:coverage\": \"vitest run --coverage\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"eslint src\",\n \"prepublishOnly\": \"pnpm build\"\n },\n \"keywords\": [\n \"aws\",\n \"ses\",\n \"email\",\n \"infrastructure\",\n \"cli\"\n ],\n \"author\": \"Wraps\",\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@aws-sdk/client-acm\": \"3.933.0\",\n \"@aws-sdk/client-cloudformation\": \"^3.490.0\",\n \"@aws-sdk/client-cloudfront\": \"3.933.0\",\n \"@aws-sdk/client-cloudwatch\": \"^3.490.0\",\n \"@aws-sdk/client-dynamodb\": \"^3.490.0\",\n \"@aws-sdk/client-iam\": \"3.932.0\",\n \"@aws-sdk/client-lambda\": \"3.925.0\",\n \"@aws-sdk/client-mailmanager\": \"3.925.0\",\n \"@aws-sdk/client-pinpoint-sms-voice-v2\": \"3.955.0\",\n \"@aws-sdk/client-route-53\": \"3.925.0\",\n \"@aws-sdk/client-ses\": \"^3.490.0\",\n \"@aws-sdk/client-sesv2\": \"3.925.0\",\n \"@aws-sdk/client-sns\": \"^3.490.0\",\n \"@aws-sdk/client-sqs\": \"3.933.0\",\n \"@aws-sdk/client-sts\": \"^3.490.0\",\n \"@aws-sdk/util-dynamodb\": \"3.927.0\",\n \"@clack/prompts\": \"^0.11.0\",\n \"@pulumi/aws\": \"^7.11.1\",\n \"@pulumi/pulumi\": \"^3.207.0\",\n \"args\": \"^5.0.3\",\n \"conf\": \"^13.0.1\",\n \"cosmiconfig\": \"^9.0.0\",\n \"esbuild\": \"^0.25.12\",\n \"express\": \"^4.21.2\",\n \"get-port\": \"^7.1.0\",\n \"http-terminator\": \"^3.2.0\",\n \"isomorphic-dompurify\": \"2.32.0\",\n \"mailparser\": \"3.9.0\",\n \"open\": \"^10.1.0\",\n \"picocolors\": \"^1.1.1\",\n \"tabtab\": \"^3.0.2\",\n \"uuid\": \"^11.0.3\"\n },\n \"devDependencies\": {\n \"@types/args\": \"5.0.4\",\n \"@types/express\": \"^5.0.0\",\n \"@types/mailparser\": \"3.4.6\",\n \"@types/node\": \"^20.11.0\",\n \"@types/uuid\": \"^10.0.0\",\n \"@vitest/coverage-v8\": \"4.0.7\",\n \"aws-sdk-client-mock\": \"4.1.0\",\n \"aws-sdk-client-mock-vitest\": \"7.0.1\",\n \"eslint\": \"^8.56.0\",\n \"tsup\": \"^8.0.1\",\n \"tsx\": \"4.20.6\",\n \"typescript\": \"catalog:\",\n \"vitest\": \"^4.0.7\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n }\n}\n","/**\n * Telemetry client for Wraps CLI\n * @module telemetry/client\n */\n\nimport { isCI } from \"../utils/shared/ci-detection.js\";\nimport { TelemetryConfigManager } from \"./config.js\";\nimport type {\n TelemetryClientOptions,\n TelemetryEvent,\n TelemetryRequest,\n} from \"./types.js\";\n\nconst DEFAULT_ENDPOINT = \"https://wraps.dev/api/telemetry\";\nconst DEFAULT_TIMEOUT = 2000; // 2 seconds\n\n/**\n * Main telemetry client for tracking CLI usage\n *\n * Features:\n * - Non-blocking event tracking with automatic batching\n * - Respects DO_NOT_TRACK and WRAPS_TELEMETRY_DISABLED environment variables\n * - Auto-disabled in CI environments\n * - 2-second timeout with silent failure\n * - Debug mode for development\n *\n * @example\n * ```typescript\n * const client = getTelemetryClient();\n *\n * client.track('command:init', {\n * service: 'email',\n * success: true\n * });\n *\n * await client.shutdown(); // Flush remaining events\n * ```\n */\nexport class TelemetryClient {\n private readonly config: TelemetryConfigManager;\n private readonly endpoint: string;\n private readonly timeout: number;\n private readonly debug: boolean;\n private enabled: boolean;\n private eventQueue: TelemetryEvent[] = [];\n private flushTimer?: NodeJS.Timeout;\n\n constructor(options: TelemetryClientOptions = {}) {\n this.config = new TelemetryConfigManager();\n this.endpoint = options.endpoint || DEFAULT_ENDPOINT;\n this.timeout = options.timeout || DEFAULT_TIMEOUT;\n this.debug = options.debug || process.env.WRAPS_TELEMETRY_DEBUG === \"1\";\n\n // Check if telemetry should be enabled\n this.enabled = this.shouldBeEnabled();\n }\n\n /**\n * Determine if telemetry should be enabled based on environment and config\n */\n private shouldBeEnabled(): boolean {\n // Check DO_NOT_TRACK first (universal standard)\n if (process.env.DO_NOT_TRACK === \"1\") {\n return false;\n }\n\n // Check Wraps-specific env var\n if (process.env.WRAPS_TELEMETRY_DISABLED === \"1\") {\n return false;\n }\n\n // Check CI environment\n if (isCI()) {\n return false;\n }\n\n // Check config file\n if (!this.config.isEnabled()) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Track an event\n *\n * @param event - Event name in format \"category:action\" (e.g., \"command:init\")\n * @param properties - Additional event properties (no PII)\n */\n track(event: string, properties?: Record<string, unknown>): void {\n const telemetryEvent: TelemetryEvent = {\n event,\n properties: {\n ...properties,\n cli_version: this.getCLIVersion(),\n os: process.platform,\n node_version: process.version,\n ci: isCI(),\n },\n anonymousId: this.config.getAnonymousId(),\n timestamp: new Date().toISOString(),\n };\n\n // Debug mode: show what would be sent (even if disabled)\n if (this.debug) {\n console.log(\n \"[Telemetry Debug] Event:\",\n JSON.stringify(telemetryEvent, null, 2)\n );\n return;\n }\n\n // Check if telemetry is enabled (after debug check)\n if (!this.enabled) {\n return;\n }\n\n // Add to queue\n this.eventQueue.push(telemetryEvent);\n\n // Flush after short delay (batch events from same command)\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n }\n this.flushTimer = setTimeout(() => this.flush(), 100);\n }\n\n /**\n * Flush queued events to server\n */\n private async flush(): Promise<void> {\n if (this.eventQueue.length === 0) {\n return;\n }\n\n const eventsToSend = [...this.eventQueue];\n this.eventQueue = [];\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const requestBody: TelemetryRequest = {\n events: eventsToSend,\n batch: true,\n };\n\n await fetch(this.endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(requestBody),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n } catch (error) {\n // Silent failure - never break user's workflow\n if (this.debug) {\n console.error(\"[Telemetry Debug] Failed to send events:\", error);\n }\n }\n }\n\n /**\n * Flush and wait for all events to be sent\n * Should be called before CLI exits\n */\n async shutdown(): Promise<void> {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n }\n await this.flush();\n }\n\n /**\n * Enable telemetry\n * Note: Won't override environment variable opt-outs (DO_NOT_TRACK, CI, etc.)\n */\n enable(): void {\n this.config.setEnabled(true);\n\n // Check if environment variables prevent telemetry\n if (\n process.env.DO_NOT_TRACK === \"1\" ||\n process.env.DO_NOT_TRACK === \"true\"\n ) {\n this.enabled = false;\n return;\n }\n\n if (process.env.WRAPS_TELEMETRY_DISABLED === \"1\") {\n this.enabled = false;\n return;\n }\n\n if (isCI()) {\n this.enabled = false;\n return;\n }\n\n // No env restrictions, enable telemetry\n this.enabled = true;\n }\n\n /**\n * Disable telemetry\n */\n disable(): void {\n this.config.setEnabled(false);\n this.enabled = false;\n this.eventQueue = [];\n }\n\n /**\n * Check if telemetry is enabled\n */\n isEnabled(): boolean {\n return this.enabled;\n }\n\n /**\n * Get config file path\n */\n getConfigPath(): string {\n return this.config.getConfigPath();\n }\n\n /**\n * Show first-run notification\n */\n shouldShowNotification(): boolean {\n return this.enabled && !this.config.hasShownNotification();\n }\n\n /**\n * Mark notification as shown\n */\n markNotificationShown(): void {\n this.config.markNotificationShown();\n }\n\n /**\n * Get CLI version from package.json\n */\n private getCLIVersion(): string {\n try {\n // Dynamic import would be better but requires async\n // Using require for now since this is CommonJS compatible\n const packageJson = require(\"../../package.json\");\n return packageJson.version;\n } catch {\n return \"unknown\";\n }\n }\n}\n\n// Singleton instance\nlet telemetryInstance: TelemetryClient | null = null;\n\n/**\n * Get the singleton telemetry client instance\n *\n * @example\n * ```typescript\n * const client = getTelemetryClient();\n * client.track('command:init', { success: true });\n * ```\n */\nexport function getTelemetryClient(): TelemetryClient {\n if (!telemetryInstance) {\n telemetryInstance = new TelemetryClient();\n }\n return telemetryInstance;\n}\n","/**\n * Event tracking helpers for Wraps CLI\n * @module telemetry/events\n */\n\nimport { getTelemetryClient } from \"./client.js\";\n\n/**\n * Track CLI command execution\n *\n * @param command - Command name (e.g., \"email:init\", \"status\")\n * @param metadata - Additional metadata about command execution\n *\n * @example\n * ```typescript\n * trackCommand('email:init', {\n * success: true,\n * duration_ms: 1500,\n * preset: 'production'\n * });\n * ```\n */\nexport function trackCommand(\n command: string,\n metadata?: {\n success?: boolean;\n duration_ms?: number;\n preset?: string;\n provider?: string;\n service?: string;\n [key: string]: unknown;\n }\n): void {\n const client = getTelemetryClient();\n\n // Sanitize metadata to ensure no PII\n const sanitized = metadata ? { ...metadata } : {};\n\n // Remove any potentially sensitive fields\n sanitized.domain = undefined;\n sanitized.accountId = undefined;\n sanitized.email = undefined;\n\n client.track(`command:${command}`, sanitized);\n}\n\n/**\n * Track service initialization\n *\n * @param service - Service type (email, sms, etc.)\n * @param success - Whether initialization succeeded\n * @param metadata - Additional metadata\n *\n * @example\n * ```typescript\n * trackServiceInit('email', true, {\n * preset: 'production',\n * provider: 'vercel'\n * });\n * ```\n */\nexport function trackServiceInit(\n service: string,\n success: boolean,\n metadata?: {\n preset?: string;\n provider?: string;\n features?: string[];\n duration_ms?: number;\n [key: string]: unknown;\n }\n): void {\n const client = getTelemetryClient();\n\n client.track(\"service:init\", {\n service,\n success,\n ...metadata,\n });\n}\n\n/**\n * Track service deployment\n *\n * @param service - Service type (email, sms, etc.)\n * @param metadata - Deployment metadata\n *\n * @example\n * ```typescript\n * trackServiceDeployed('email', {\n * duration_ms: 45000,\n * features: ['tracking', 'history']\n * });\n * ```\n */\nexport function trackServiceDeployed(\n service: string,\n metadata?: {\n duration_ms?: number;\n features?: string[];\n preset?: string;\n [key: string]: unknown;\n }\n): void {\n const client = getTelemetryClient();\n\n client.track(\"service:deployed\", {\n service,\n ...metadata,\n });\n}\n\n/**\n * Track dashboard/console start\n *\n * @param mode - Console mode (local or hosted)\n * @param metadata - Additional metadata\n *\n * @example\n * ```typescript\n * trackConsoleStart('local', { port: 3100 });\n * ```\n */\nexport function trackConsoleStart(\n mode: \"local\" | \"hosted\",\n metadata?: Record<string, unknown>\n): void {\n const client = getTelemetryClient();\n\n client.track(\"console:started\", {\n mode,\n ...metadata,\n });\n}\n\n/**\n * Track console stop\n *\n * @param metadata - Stop metadata (e.g., duration)\n *\n * @example\n * ```typescript\n * trackConsoleStop({ duration_s: 300 });\n * ```\n */\nexport function trackConsoleStop(metadata?: {\n duration_s?: number;\n [key: string]: unknown;\n}): void {\n const client = getTelemetryClient();\n\n client.track(\"console:stopped\", metadata || {});\n}\n\n/**\n * Track error occurrence\n *\n * IMPORTANT: Never include error messages, only error codes\n * Error messages may contain sensitive information\n *\n * @param errorCode - Error code (e.g., \"AWS_CREDENTIALS_INVALID\")\n * @param command - Command where error occurred\n * @param metadata - Additional metadata\n *\n * @example\n * ```typescript\n * trackError('AWS_CREDENTIALS_INVALID', 'email:init', {\n * step: 'credential_validation'\n * });\n * ```\n */\nexport function trackError(\n errorCode: string,\n command: string,\n metadata?: Record<string, unknown>\n): void {\n const client = getTelemetryClient();\n\n client.track(\"error:occurred\", {\n error_code: errorCode,\n command,\n ...metadata,\n });\n}\n\n/**\n * Track feature usage\n *\n * @param feature - Feature name\n * @param metadata - Feature metadata\n *\n * @example\n * ```typescript\n * trackFeature('domain_verified', {\n * dns_provider: 'route53',\n * auto_detected: true\n * });\n * ```\n */\nexport function trackFeature(\n feature: string,\n metadata?: Record<string, unknown>\n): void {\n const client = getTelemetryClient();\n\n client.track(`feature:${feature}`, metadata || {});\n}\n\n/**\n * Track service upgrade\n *\n * @param service - Service type\n * @param metadata - Upgrade metadata\n *\n * @example\n * ```typescript\n * trackServiceUpgrade('email', {\n * from_preset: 'starter',\n * to_preset: 'production',\n * added_features: ['history', 'dedicated_ip']\n * });\n * ```\n */\nexport function trackServiceUpgrade(\n service: string,\n metadata?: {\n from_preset?: string;\n to_preset?: string;\n added_features?: string[];\n [key: string]: unknown;\n }\n): void {\n const client = getTelemetryClient();\n\n client.track(\"service:upgraded\", {\n service,\n ...metadata,\n });\n}\n\n/**\n * Track service removal\n *\n * @param service - Service type\n * @param metadata - Removal metadata\n *\n * @example\n * ```typescript\n * trackServiceRemoved('email', { reason: 'user_initiated' });\n * ```\n */\nexport function trackServiceRemoved(\n service: string,\n metadata?: Record<string, unknown>\n): void {\n const client = getTelemetryClient();\n\n client.track(\"service:removed\", {\n service,\n ...metadata,\n });\n}\n","import * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { trackError } from \"../../telemetry/events.js\";\n\n/**\n * Custom error class for Wraps CLI errors\n */\nexport class WrapsError extends Error {\n constructor(\n message: string,\n public code: string,\n public suggestion?: string,\n public docsUrl?: string\n ) {\n super(message);\n this.name = \"WrapsError\";\n }\n}\n\n/**\n * Global error handler for CLI errors\n * Formats and displays errors with suggestions and docs\n */\nexport function handleCLIError(error: unknown): never {\n console.error(\"\"); // Blank line\n\n if (error instanceof WrapsError) {\n // Track error (code only, never message)\n trackError(error.code, \"unknown\");\n\n clack.log.error(error.message);\n\n if (error.suggestion) {\n console.log(`\\n${pc.yellow(\"Suggestion:\")}`);\n console.log(` ${pc.white(error.suggestion)}\\n`);\n }\n\n if (error.docsUrl) {\n console.log(`${pc.dim(\"Documentation:\")}`);\n console.log(` ${pc.blue(error.docsUrl)}\\n`);\n }\n\n process.exit(1);\n }\n\n // Unknown error\n trackError(\"UNKNOWN_ERROR\", \"unknown\");\n\n clack.log.error(\"An unexpected error occurred\");\n console.error(error);\n console.log(`\\n${pc.dim(\"If this persists, please report at:\")}`);\n console.log(` ${pc.blue(\"https://github.com/wraps-team/wraps/issues\")}\\n`);\n process.exit(1);\n}\n\n/**\n * Common error factory functions\n */\nexport const errors = {\n noAWSCredentials: () =>\n new WrapsError(\n \"AWS credentials not found\",\n \"NO_AWS_CREDENTIALS\",\n \"Run: aws configure\\nOr set AWS_PROFILE environment variable\",\n \"https://wraps.dev/docs/setup/aws-credentials\"\n ),\n\n stackExists: (stackName: string) =>\n new WrapsError(\n `Stack \"${stackName}\" already exists`,\n \"STACK_EXISTS\",\n `To update: wraps email upgrade\\nTo remove: wraps destroy --stack ${stackName}`,\n \"https://wraps.dev/docs/cli/upgrade\"\n ),\n\n invalidRegion: (region: string) =>\n new WrapsError(\n `Invalid AWS region: ${region}`,\n \"INVALID_REGION\",\n \"Use a valid AWS region like: us-east-1, eu-west-1, ap-southeast-1\",\n \"https://docs.aws.amazon.com/general/latest/gr/rande.html\"\n ),\n\n pulumiError: (message: string) =>\n new WrapsError(\n `Infrastructure deployment failed: ${message}`,\n \"PULUMI_ERROR\",\n \"Check your AWS permissions and try again\",\n \"https://wraps.dev/docs/troubleshooting\"\n ),\n\n noStack: () =>\n new WrapsError(\n \"No Wraps infrastructure found in this AWS account\",\n \"NO_STACK\",\n \"Run: wraps email init\\nTo deploy new infrastructure\",\n \"https://wraps.dev/docs/cli/init\"\n ),\n\n pulumiNotInstalled: () =>\n new WrapsError(\n \"Pulumi CLI is not installed\",\n \"PULUMI_NOT_INSTALLED\",\n \"Install Pulumi:\\n macOS: brew install pulumi/tap/pulumi\\n Linux: curl -fsSL https://get.pulumi.com | sh\\n Windows: choco install pulumi\\n\\nOr download from: https://www.pulumi.com/docs/install/\",\n \"https://www.pulumi.com/docs/install/\"\n ),\n\n stackLocked: () =>\n new WrapsError(\n \"The Pulumi stack is locked from a previous run\",\n \"STACK_LOCKED\",\n \"This happens when a previous deployment was interrupted.\\n\\nTo unlock, run:\\n rm -rf ~/.wraps/pulumi/.pulumi/locks\\n\\nThen try your command again.\",\n \"https://wraps.dev/docs/troubleshooting\"\n ),\n\n // SMS-specific errors\n smsNotConfigured: () =>\n new WrapsError(\n \"SMS infrastructure not found\",\n \"SMS_NOT_CONFIGURED\",\n \"Run: wraps sms init\\nTo deploy SMS infrastructure\",\n \"https://wraps.dev/docs/sms/init\"\n ),\n\n smsPhoneNotVerified: () =>\n new WrapsError(\n \"Phone number registration not complete\",\n \"SMS_PHONE_NOT_VERIFIED\",\n \"Toll-free numbers require registration (15+ days).\\nCheck status in AWS console.\",\n \"https://wraps.dev/docs/sms/registration\"\n ),\n\n smsOptedOut: (phoneNumber: string) =>\n new WrapsError(\n `Destination number ${phoneNumber} has opted out`,\n \"SMS_OPTED_OUT\",\n \"The recipient has opted out of receiving messages.\\nThey can opt back in by texting START to your number.\",\n \"https://wraps.dev/docs/sms/opt-out\"\n ),\n\n smsSpendingLimit: () =>\n new WrapsError(\n \"AWS SMS spending limit reached\",\n \"SMS_SPENDING_LIMIT\",\n \"Request a spending limit increase in the AWS console:\\nAWS → End User Messaging → Account Settings → Spending Limits\",\n \"https://docs.aws.amazon.com/sms-voice/latest/userguide/spend-limit-increase.html\"\n ),\n\n smsInvalidPhoneNumber: (phoneNumber: string) =>\n new WrapsError(\n `Invalid phone number format: ${phoneNumber}`,\n \"SMS_INVALID_PHONE_NUMBER\",\n \"Phone numbers must be in E.164 format:\\n Example: +14155551234 (US)\\n Example: +447911123456 (UK)\",\n \"https://wraps.dev/docs/sms/phone-format\"\n ),\n\n smsSimulatorLimit: () =>\n new WrapsError(\n \"Simulator daily message limit reached (100 messages)\",\n \"SMS_SIMULATOR_LIMIT\",\n \"Upgrade to a toll-free number for production use:\\n wraps sms upgrade --phone-type toll-free\",\n \"https://wraps.dev/docs/sms/upgrade\"\n ),\n};\n","import { ACMClient, DescribeCertificateCommand } from \"@aws-sdk/client-acm\";\nimport {\n GetIdentityVerificationAttributesCommand,\n ListIdentitiesCommand,\n SESClient,\n} from \"@aws-sdk/client-ses\";\nimport { GetCallerIdentityCommand, STSClient } from \"@aws-sdk/client-sts\";\nimport { errors } from \"./errors.js\";\n\n/**\n * AWS identity information\n */\nexport type AWSIdentity = {\n accountId: string;\n userId: string;\n arn: string;\n};\n\n/**\n * Validate AWS credentials by calling STS GetCallerIdentity\n */\nexport async function validateAWSCredentials(): Promise<AWSIdentity> {\n const sts = new STSClient({ region: \"us-east-1\" });\n\n try {\n const identity = await sts.send(new GetCallerIdentityCommand({}));\n return {\n accountId: identity.Account!,\n userId: identity.UserId!,\n arn: identity.Arn!,\n };\n } catch (_error) {\n throw errors.noAWSCredentials();\n }\n}\n\n/**\n * Check if a region is valid\n */\nexport async function checkRegion(region: string): Promise<boolean> {\n // List of valid AWS regions (as of 2025)\n const validRegions = [\n \"us-east-1\",\n \"us-east-2\",\n \"us-west-1\",\n \"us-west-2\",\n \"af-south-1\",\n \"ap-east-1\",\n \"ap-south-1\",\n \"ap-northeast-1\",\n \"ap-northeast-2\",\n \"ap-northeast-3\",\n \"ap-southeast-1\",\n \"ap-southeast-2\",\n \"ap-southeast-3\",\n \"ca-central-1\",\n \"eu-central-1\",\n \"eu-west-1\",\n \"eu-west-2\",\n \"eu-west-3\",\n \"eu-south-1\",\n \"eu-north-1\",\n \"me-south-1\",\n \"sa-east-1\",\n ];\n\n return validRegions.includes(region);\n}\n\n/**\n * Get AWS region from environment or config\n */\nexport async function getAWSRegion(): Promise<string> {\n // Try to detect region from various sources\n if (process.env.AWS_REGION) {\n return process.env.AWS_REGION;\n }\n if (process.env.AWS_DEFAULT_REGION) {\n return process.env.AWS_DEFAULT_REGION;\n }\n\n // Default fallback\n return \"us-east-1\";\n}\n\n/**\n * SES domain identity\n */\nexport type SESDomain = {\n domain: string;\n verified: boolean;\n};\n\n/**\n * List all SES identities (domains) in the account\n */\nexport async function listSESDomains(region: string): Promise<SESDomain[]> {\n const ses = new SESClient({ region });\n\n try {\n // Get all identities\n const identitiesResponse = await ses.send(\n new ListIdentitiesCommand({\n IdentityType: \"Domain\",\n })\n );\n\n const identities = identitiesResponse.Identities || [];\n\n if (identities.length === 0) {\n return [];\n }\n\n // Get verification attributes\n const attributesResponse = await ses.send(\n new GetIdentityVerificationAttributesCommand({\n Identities: identities,\n })\n );\n\n const attributes = attributesResponse.VerificationAttributes || {};\n\n // Map to SESDomain objects\n return identities.map((domain) => ({\n domain,\n verified: attributes[domain]?.VerificationStatus === \"Success\",\n }));\n } catch (error) {\n console.error(\"Error listing SES domains:\", error);\n return [];\n }\n}\n\n/**\n * Check if SES is in sandbox mode\n */\nexport async function isSESSandbox(region: string): Promise<boolean> {\n const ses = new SESClient({ region });\n\n try {\n // In sandbox mode, you can only send to verified addresses\n // This is a heuristic - we check if there are any identities\n await ses.send(\n new ListIdentitiesCommand({\n MaxItems: 1,\n })\n );\n\n // If we can call this API, SES is enabled\n // The actual sandbox check requires checking send quota\n // For now, we'll return false (not sandbox) if the API works\n return false;\n } catch (error: any) {\n // If we get an error about SES not being enabled, return true\n if (error.name === \"InvalidParameterValue\") {\n return true;\n }\n throw error;\n }\n}\n\n/**\n * ACM certificate status\n */\nexport type ACMCertificateStatus = {\n status: string;\n domainName: string;\n validationRecords: Array<{\n name: string;\n type: string;\n value: string;\n }>;\n};\n\n/**\n * Check ACM certificate validation status\n * Note: ACM certificates for CloudFront must be in us-east-1\n */\nexport async function getACMCertificateStatus(\n certificateArn: string\n): Promise<ACMCertificateStatus | null> {\n const acm = new ACMClient({ region: \"us-east-1\" });\n\n try {\n const response = await acm.send(\n new DescribeCertificateCommand({\n CertificateArn: certificateArn,\n })\n );\n\n const certificate = response.Certificate;\n if (!certificate) {\n return null;\n }\n\n // Extract validation records\n const validationRecords =\n certificate.DomainValidationOptions?.map((option) => ({\n name: option.ResourceRecord?.Name || \"\",\n type: option.ResourceRecord?.Type || \"\",\n value: option.ResourceRecord?.Value || \"\",\n })) || [];\n\n return {\n status: certificate.Status || \"UNKNOWN\",\n domainName: certificate.DomainName || \"\",\n validationRecords,\n };\n } catch (error) {\n console.error(\"Error getting ACM certificate status:\", error);\n return null;\n }\n}\n","import { randomBytes } from \"node:crypto\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as aws from \"@pulumi/aws\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport { build } from \"esbuild\";\n\n/**\n * Get the package root directory (where package.json lives)\n * Works both in development (src/) and production (dist/)\n */\nfunction getPackageRoot(): string {\n const currentFile = fileURLToPath(import.meta.url);\n let dir = dirname(currentFile);\n\n // Walk up the directory tree until we find package.json\n while (dir !== dirname(dir)) {\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n dir = dirname(dir);\n }\n\n throw new Error(\"Could not find package.json\");\n}\n\n/**\n * Lambda configuration\n */\nexport type LambdaConfig = {\n roleArn: pulumi.Output<string>;\n tableName: pulumi.Output<string>;\n queueArn: pulumi.Output<string>;\n accountId: string;\n region: string;\n};\n\n/**\n * Lambda functions output\n */\nexport type LambdaFunctions = {\n eventProcessor: aws.lambda.Function;\n eventSourceMapping: aws.lambda.EventSourceMapping;\n};\n\n/**\n * Check if Lambda function exists\n */\nasync function lambdaFunctionExists(functionName: string): Promise<boolean> {\n try {\n const { LambdaClient, GetFunctionCommand } = await import(\n \"@aws-sdk/client-lambda\"\n );\n const lambda = new LambdaClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n\n await lambda.send(new GetFunctionCommand({ FunctionName: functionName }));\n return true;\n } catch (error: any) {\n if (error.name === \"ResourceNotFoundException\") {\n return false;\n }\n console.error(\"Error checking for existing Lambda function:\", error);\n return false;\n }\n}\n\n/**\n * Find existing event source mapping for Lambda function and SQS queue\n */\nasync function findEventSourceMapping(\n functionName: string,\n queueArn: string\n): Promise<string | null> {\n try {\n const { LambdaClient, ListEventSourceMappingsCommand } = await import(\n \"@aws-sdk/client-lambda\"\n );\n const lambda = new LambdaClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n\n const response = await lambda.send(\n new ListEventSourceMappingsCommand({\n FunctionName: functionName,\n EventSourceArn: queueArn,\n })\n );\n\n // Return UUID of the first matching event source mapping\n return response.EventSourceMappings?.[0]?.UUID || null;\n } catch (error: any) {\n console.error(\"Error finding event source mapping:\", error);\n return null;\n }\n}\n\n/**\n * Get the Lambda function code directory\n *\n * In production (published package), uses pre-bundled code from dist/lambda/\n * In development, bundles the TypeScript source on-the-fly\n */\nexport async function getLambdaCode(functionName: string): Promise<string> {\n const packageRoot = getPackageRoot();\n\n // Check for pre-bundled Lambda code in dist/ (production - published package)\n const distLambdaPath = join(packageRoot, \"dist\", \"lambda\", functionName);\n const distBundleMarker = join(distLambdaPath, \".bundled\");\n\n if (existsSync(distBundleMarker)) {\n // Use pre-bundled code from dist/\n return distLambdaPath;\n }\n\n // Check for pre-bundled Lambda code in lambda/ (development build)\n const lambdaPath = join(packageRoot, \"lambda\", functionName);\n const lambdaBundleMarker = join(lambdaPath, \".bundled\");\n\n if (existsSync(lambdaBundleMarker)) {\n // Use pre-bundled code from lambda/\n return lambdaPath;\n }\n\n // Development mode: bundle on-the-fly from TypeScript source\n const sourcePath = join(lambdaPath, \"index.ts\");\n\n if (!existsSync(sourcePath)) {\n throw new Error(\n `Lambda source not found: ${sourcePath}\\n` +\n `This usually means the build process didn't complete successfully.\\n` +\n \"Try running: pnpm build\"\n );\n }\n\n const buildId = randomBytes(8).toString(\"hex\");\n const outdir = join(tmpdir(), `wraps-lambda-${buildId}`);\n\n if (!existsSync(outdir)) {\n mkdirSync(outdir, { recursive: true });\n }\n\n // Bundle with esbuild\n await build({\n entryPoints: [sourcePath],\n bundle: true,\n platform: \"node\",\n target: \"node24\",\n format: \"esm\",\n outfile: join(outdir, \"index.mjs\"),\n external: [\"@aws-sdk/*\"], // AWS SDK v3 is included in Lambda runtime\n minify: true,\n sourcemap: false,\n });\n\n return outdir;\n}\n\n/**\n * Deploy Lambda functions for email event processing\n *\n * Architecture:\n * SQS Queue -> Lambda (event-processor) -> DynamoDB\n *\n * The Lambda function is triggered by SQS via Event Source Mapping.\n * Failed messages are automatically sent to the DLQ after 3 retries.\n */\nexport async function deployLambdaFunctions(\n config: LambdaConfig\n): Promise<LambdaFunctions> {\n // Get Lambda code directory (pre-bundled in production, bundled on-the-fly in dev)\n const eventProcessorCode = await getLambdaCode(\"event-processor\");\n\n // IAM role for Lambda execution\n const lambdaRole = new aws.iam.Role(\"wraps-email-lambda-role\", {\n assumeRolePolicy: JSON.stringify({\n Version: \"2012-10-17\",\n Statement: [\n {\n Effect: \"Allow\",\n Principal: { Service: \"lambda.amazonaws.com\" },\n Action: \"sts:AssumeRole\",\n },\n ],\n }),\n tags: {\n ManagedBy: \"wraps-cli\",\n },\n });\n\n // Attach basic Lambda execution policy\n new aws.iam.RolePolicyAttachment(\"wraps-email-lambda-basic-execution\", {\n role: lambdaRole.name,\n policyArn:\n \"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole\",\n });\n\n // Lambda policy for DynamoDB and SQS\n new aws.iam.RolePolicy(\"wraps-email-lambda-policy\", {\n role: lambdaRole.name,\n policy: pulumi\n .all([config.tableName, config.queueArn])\n .apply(([tableName, queueArn]) =>\n JSON.stringify({\n Version: \"2012-10-17\",\n Statement: [\n {\n // DynamoDB access\n Effect: \"Allow\",\n Action: [\n \"dynamodb:PutItem\",\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n \"dynamodb:Scan\",\n \"dynamodb:UpdateItem\",\n ],\n Resource: [\n `arn:aws:dynamodb:*:*:table/${tableName}`,\n `arn:aws:dynamodb:*:*:table/${tableName}/index/*`,\n ],\n },\n {\n // SQS access for event source mapping\n Effect: \"Allow\",\n Action: [\n \"sqs:ReceiveMessage\",\n \"sqs:DeleteMessage\",\n \"sqs:GetQueueAttributes\",\n ],\n Resource: queueArn,\n },\n ],\n })\n ),\n });\n\n // Check if Lambda function already exists\n const functionName = \"wraps-email-event-processor\";\n const exists = await lambdaFunctionExists(functionName);\n\n // Create event-processor Lambda\n const eventProcessor = exists\n ? new aws.lambda.Function(\n functionName,\n {\n name: functionName,\n runtime: \"nodejs24.x\",\n handler: \"index.handler\",\n role: lambdaRole.arn,\n code: new pulumi.asset.FileArchive(eventProcessorCode),\n timeout: 300, // 5 minutes (matches SQS visibility timeout)\n memorySize: 512,\n environment: {\n variables: {\n TABLE_NAME: config.tableName,\n AWS_ACCOUNT_ID: config.accountId,\n },\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n Description:\n \"Process SES email events from SQS and store in DynamoDB\",\n },\n },\n {\n import: functionName, // Import existing function\n }\n )\n : new aws.lambda.Function(functionName, {\n name: functionName,\n runtime: \"nodejs24.x\",\n handler: \"index.handler\",\n role: lambdaRole.arn,\n code: new pulumi.asset.FileArchive(eventProcessorCode),\n timeout: 300, // 5 minutes (matches SQS visibility timeout)\n memorySize: 512,\n environment: {\n variables: {\n TABLE_NAME: config.tableName,\n AWS_ACCOUNT_ID: config.accountId,\n },\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n Description:\n \"Process SES email events from SQS and store in DynamoDB\",\n },\n });\n\n // Check if event source mapping already exists\n // Construct the queue ARN from the known queue name, region, and account ID\n const queueArnValue = `arn:aws:sqs:${config.region}:${config.accountId}:wraps-email-events`;\n const existingMappingUuid = await findEventSourceMapping(\n functionName,\n queueArnValue\n );\n\n // Create SQS event source mapping for Lambda\n // This automatically polls SQS and invokes the Lambda function\n const mappingConfig = {\n eventSourceArn: config.queueArn,\n functionName: eventProcessor.name,\n batchSize: 10, // Process up to 10 messages per invocation\n maximumBatchingWindowInSeconds: 5, // Wait up to 5 seconds to batch messages\n functionResponseTypes: [\"ReportBatchItemFailures\"], // Enable partial batch responses\n };\n\n const eventSourceMapping = existingMappingUuid\n ? new aws.lambda.EventSourceMapping(\n \"wraps-email-event-source-mapping\",\n mappingConfig,\n {\n import: existingMappingUuid, // Import with the UUID\n }\n )\n : new aws.lambda.EventSourceMapping(\n \"wraps-email-event-source-mapping\",\n mappingConfig\n );\n\n return {\n eventProcessor,\n eventSourceMapping,\n };\n}\n","import {\n type Change,\n ChangeResourceRecordSetsCommand,\n ListHostedZonesByNameCommand,\n ListResourceRecordSetsCommand,\n type ResourceRecordSet,\n Route53Client,\n} from \"@aws-sdk/client-route-53\";\n\n/**\n * Proposed DNS record with conflict detection info\n */\nexport type ProposedDNSRecord = {\n name: string;\n type: \"CNAME\" | \"TXT\" | \"MX\";\n proposedValue: string;\n existingValue: string | null;\n status: \"new\" | \"update\" | \"conflict\" | \"no_change\";\n category: \"dkim\" | \"spf\" | \"dmarc\" | \"tracking\" | \"mailfrom_mx\" | \"mailfrom_spf\";\n conflictReason?: string;\n};\n\n/**\n * DNS preview result with all proposed changes\n */\nexport type DNSPreviewResult = {\n records: ProposedDNSRecord[];\n hasConflicts: boolean;\n conflictCount: number;\n newCount: number;\n updateCount: number;\n noChangeCount: number;\n};\n\n/**\n * Get existing TXT records for a domain\n * Returns all TXT record values and identifies which one is SPF\n */\nasync function getExistingTXTRecords(\n client: Route53Client,\n hostedZoneId: string,\n domain: string\n): Promise<{ allValues: string[]; spfValue: string | null; ttl: number }> {\n try {\n const response = await client.send(\n new ListResourceRecordSetsCommand({\n HostedZoneId: hostedZoneId,\n StartRecordName: domain,\n StartRecordType: \"TXT\",\n MaxItems: 100,\n })\n );\n\n // Find TXT records for the exact domain\n const txtRecordSet = response.ResourceRecordSets?.find(\n (rs) =>\n rs.Type === \"TXT\" && (rs.Name === domain || rs.Name === `${domain}.`)\n );\n\n if (!txtRecordSet?.ResourceRecords) {\n return { allValues: [], spfValue: null, ttl: 1800 };\n }\n\n const allValues: string[] = [];\n let spfValue: string | null = null;\n\n for (const record of txtRecordSet.ResourceRecords) {\n const value = record.Value || \"\";\n allValues.push(value);\n\n // Check if this is the SPF record (strip quotes for comparison)\n const unquoted = value.replace(/^\"|\"$/g, \"\");\n if (unquoted.startsWith(\"v=spf1\")) {\n spfValue = unquoted;\n }\n }\n\n return {\n allValues,\n spfValue,\n ttl: txtRecordSet.TTL || 1800,\n };\n } catch (_error) {\n return { allValues: [], spfValue: null, ttl: 1800 };\n }\n}\n\n/**\n * Merge amazonses.com include into an existing SPF record\n * If the record already includes amazonses.com, returns unchanged\n */\nfunction mergeSPFRecord(existingSPF: string): string {\n const sesInclude = \"include:amazonses.com\";\n\n // Already includes SES\n if (existingSPF.includes(sesInclude)) {\n return existingSPF;\n }\n\n // Find the position before the \"all\" mechanism to insert our include\n // SPF format: v=spf1 [mechanisms...] [qualifier]all\n const allMatch = existingSPF.match(/\\s([~+?-]?all)$/);\n\n if (allMatch) {\n // Insert before the \"all\" mechanism\n const beforeAll = existingSPF.slice(0, allMatch.index);\n const allPart = allMatch[1];\n return `${beforeAll} ${sesInclude} ${allPart}`;\n }\n\n // No \"all\" mechanism found, append to end\n return `${existingSPF} ${sesInclude}`;\n}\n\n// Export for testing\nexport { mergeSPFRecord };\n\n/**\n * Get all existing records from a hosted zone for comparison\n */\nasync function getExistingRecords(\n client: Route53Client,\n hostedZoneId: string\n): Promise<ResourceRecordSet[]> {\n try {\n const response = await client.send(\n new ListResourceRecordSetsCommand({\n HostedZoneId: hostedZoneId,\n MaxItems: 500,\n })\n );\n return response.ResourceRecordSets || [];\n } catch (_error) {\n return [];\n }\n}\n\n/**\n * Find an existing record by name and type\n */\nfunction findExistingRecord(\n records: ResourceRecordSet[],\n name: string,\n type: string\n): ResourceRecordSet | null {\n const normalizedName = name.endsWith(\".\") ? name : `${name}.`;\n return (\n records.find((r) => r.Name === normalizedName && r.Type === type) || null\n );\n}\n\n/**\n * Extract the value(s) from a record set as a string\n */\nfunction getRecordValue(record: ResourceRecordSet | null): string | null {\n if (!record?.ResourceRecords?.length) return null;\n return record.ResourceRecords.map((r) => r.Value || \"\").join(\", \");\n}\n\n/**\n * Preview DNS changes before applying them\n * Returns detailed info about what will be created, updated, or conflict\n */\nexport async function previewDNSChanges(\n hostedZoneId: string,\n domain: string,\n dkimTokens: string[],\n region: string,\n customTrackingDomain?: string,\n mailFromDomain?: string\n): Promise<DNSPreviewResult> {\n const client = new Route53Client({ region });\n const existingRecords = await getExistingRecords(client, hostedZoneId);\n const existingTXT = await getExistingTXTRecords(client, hostedZoneId, domain);\n\n const records: ProposedDNSRecord[] = [];\n\n // DKIM CNAME records\n for (const token of dkimTokens) {\n const name = `${token}._domainkey.${domain}`;\n const proposedValue = `${token}.dkim.amazonses.com`;\n const existing = findExistingRecord(existingRecords, name, \"CNAME\");\n const existingValue = getRecordValue(existing);\n\n let status: ProposedDNSRecord[\"status\"] = \"new\";\n if (existingValue === proposedValue) {\n status = \"no_change\";\n } else if (existingValue) {\n status = \"update\";\n }\n\n records.push({\n name,\n type: \"CNAME\",\n proposedValue,\n existingValue,\n status,\n category: \"dkim\",\n });\n }\n\n // SPF record - check for conflicts with existing SPF\n const proposedSPF = existingTXT.spfValue\n ? mergeSPFRecord(existingTXT.spfValue)\n : \"v=spf1 include:amazonses.com ~all\";\n\n let spfStatus: ProposedDNSRecord[\"status\"] = \"new\";\n let spfConflictReason: string | undefined;\n\n if (existingTXT.spfValue) {\n if (existingTXT.spfValue === proposedSPF) {\n spfStatus = \"no_change\";\n } else if (existingTXT.spfValue.includes(\"include:amazonses.com\")) {\n spfStatus = \"no_change\"; // Already has SES\n } else {\n // We're modifying an existing SPF - this is a merge, show as update\n spfStatus = \"update\";\n }\n }\n\n records.push({\n name: domain,\n type: \"TXT\",\n proposedValue: `\"${proposedSPF}\"`,\n existingValue: existingTXT.spfValue ? `\"${existingTXT.spfValue}\"` : null,\n status: spfStatus,\n category: \"spf\",\n conflictReason: spfConflictReason,\n });\n\n // DMARC record - check for existing DMARC\n const dmarcName = `_dmarc.${domain}`;\n const dmarcRuaDomain = mailFromDomain || domain;\n const proposedDMARC = `\"v=DMARC1; p=quarantine; rua=mailto:postmaster@${dmarcRuaDomain}\"`;\n const existingDMARC = findExistingRecord(existingRecords, dmarcName, \"TXT\");\n const existingDMARCValue = getRecordValue(existingDMARC);\n\n let dmarcStatus: ProposedDNSRecord[\"status\"] = \"new\";\n let dmarcConflictReason: string | undefined;\n\n if (existingDMARCValue) {\n // Check if it's the same\n if (existingDMARCValue === proposedDMARC) {\n dmarcStatus = \"no_change\";\n } else {\n // Existing DMARC will be replaced - this is a conflict!\n dmarcStatus = \"conflict\";\n dmarcConflictReason = \"Existing DMARC policy will be replaced\";\n }\n }\n\n records.push({\n name: dmarcName,\n type: \"TXT\",\n proposedValue: proposedDMARC,\n existingValue: existingDMARCValue,\n status: dmarcStatus,\n category: \"dmarc\",\n conflictReason: dmarcConflictReason,\n });\n\n // Custom tracking domain CNAME\n if (customTrackingDomain) {\n const proposedTracking = `r.${region}.awstrack.me`;\n const existingTracking = findExistingRecord(\n existingRecords,\n customTrackingDomain,\n \"CNAME\"\n );\n const existingTrackingValue = getRecordValue(existingTracking);\n\n let trackingStatus: ProposedDNSRecord[\"status\"] = \"new\";\n let trackingConflictReason: string | undefined;\n\n if (existingTrackingValue === proposedTracking) {\n trackingStatus = \"no_change\";\n } else if (existingTrackingValue) {\n trackingStatus = \"conflict\";\n trackingConflictReason = `Points to ${existingTrackingValue}, will be replaced`;\n }\n\n records.push({\n name: customTrackingDomain,\n type: \"CNAME\",\n proposedValue: proposedTracking,\n existingValue: existingTrackingValue,\n status: trackingStatus,\n category: \"tracking\",\n conflictReason: trackingConflictReason,\n });\n }\n\n // MAIL FROM domain records\n if (mailFromDomain) {\n // MX record\n const proposedMX = `10 feedback-smtp.${region}.amazonses.com`;\n const existingMX = findExistingRecord(existingRecords, mailFromDomain, \"MX\");\n const existingMXValue = getRecordValue(existingMX);\n\n let mxStatus: ProposedDNSRecord[\"status\"] = \"new\";\n if (existingMXValue === proposedMX) {\n mxStatus = \"no_change\";\n } else if (existingMXValue) {\n mxStatus = \"update\";\n }\n\n records.push({\n name: mailFromDomain,\n type: \"MX\",\n proposedValue: proposedMX,\n existingValue: existingMXValue,\n status: mxStatus,\n category: \"mailfrom_mx\",\n });\n\n // SPF for MAIL FROM subdomain\n const mailFromSPF = '\"v=spf1 include:amazonses.com ~all\"';\n const existingMailFromTXT = await getExistingTXTRecords(\n client,\n hostedZoneId,\n mailFromDomain\n );\n\n let mailFromSpfStatus: ProposedDNSRecord[\"status\"] = \"new\";\n if (\n existingMailFromTXT.spfValue?.includes(\"include:amazonses.com\")\n ) {\n mailFromSpfStatus = \"no_change\";\n } else if (existingMailFromTXT.spfValue) {\n mailFromSpfStatus = \"update\";\n }\n\n records.push({\n name: mailFromDomain,\n type: \"TXT\",\n proposedValue: mailFromSPF,\n existingValue: existingMailFromTXT.spfValue\n ? `\"${existingMailFromTXT.spfValue}\"`\n : null,\n status: mailFromSpfStatus,\n category: \"mailfrom_spf\",\n });\n }\n\n // Count statuses\n const conflictCount = records.filter((r) => r.status === \"conflict\").length;\n const newCount = records.filter((r) => r.status === \"new\").length;\n const updateCount = records.filter((r) => r.status === \"update\").length;\n const noChangeCount = records.filter((r) => r.status === \"no_change\").length;\n\n return {\n records,\n hasConflicts: conflictCount > 0,\n conflictCount,\n newCount,\n updateCount,\n noChangeCount,\n };\n}\n\n/**\n * Create selected DNS records in Route53\n * Only creates records that are in the selectedRecords set\n */\nexport async function createSelectedDNSRecords(\n hostedZoneId: string,\n domain: string,\n dkimTokens: string[],\n region: string,\n selectedCategories: Set<ProposedDNSRecord[\"category\"]>,\n customTrackingDomain?: string,\n mailFromDomain?: string\n): Promise<void> {\n const client = new Route53Client({ region });\n const changes: Change[] = [];\n\n // DKIM CNAME records\n if (selectedCategories.has(\"dkim\")) {\n for (const token of dkimTokens) {\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: `${token}._domainkey.${domain}`,\n Type: \"CNAME\",\n TTL: 1800,\n ResourceRecords: [{ Value: `${token}.dkim.amazonses.com` }],\n },\n });\n }\n }\n\n // SPF TXT record\n if (selectedCategories.has(\"spf\")) {\n const existingTXT = await getExistingTXTRecords(\n client,\n hostedZoneId,\n domain\n );\n const newTXTValues: string[] = [];\n\n if (existingTXT.spfValue) {\n const mergedSPF = mergeSPFRecord(existingTXT.spfValue);\n newTXTValues.push(`\"${mergedSPF}\"`);\n for (const value of existingTXT.allValues) {\n const unquoted = value.replace(/^\"|\"$/g, \"\");\n if (!unquoted.startsWith(\"v=spf1\")) {\n newTXTValues.push(value);\n }\n }\n } else if (existingTXT.allValues.length > 0) {\n newTXTValues.push('\"v=spf1 include:amazonses.com ~all\"');\n newTXTValues.push(...existingTXT.allValues);\n } else {\n newTXTValues.push('\"v=spf1 include:amazonses.com ~all\"');\n }\n\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: domain,\n Type: \"TXT\",\n TTL: existingTXT.ttl,\n ResourceRecords: newTXTValues.map((v) => ({ Value: v })),\n },\n });\n }\n\n // DMARC TXT record\n if (selectedCategories.has(\"dmarc\")) {\n const dmarcRuaDomain = mailFromDomain || domain;\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: `_dmarc.${domain}`,\n Type: \"TXT\",\n TTL: 1800,\n ResourceRecords: [\n {\n Value: `\"v=DMARC1; p=quarantine; rua=mailto:postmaster@${dmarcRuaDomain}\"`,\n },\n ],\n },\n });\n }\n\n // Custom tracking domain CNAME\n if (selectedCategories.has(\"tracking\") && customTrackingDomain) {\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: customTrackingDomain,\n Type: \"CNAME\",\n TTL: 1800,\n ResourceRecords: [{ Value: `r.${region}.awstrack.me` }],\n },\n });\n }\n\n // MAIL FROM domain records\n if (selectedCategories.has(\"mailfrom_mx\") && mailFromDomain) {\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: mailFromDomain,\n Type: \"MX\",\n TTL: 1800,\n ResourceRecords: [\n { Value: `10 feedback-smtp.${region}.amazonses.com` },\n ],\n },\n });\n }\n\n if (selectedCategories.has(\"mailfrom_spf\") && mailFromDomain) {\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: mailFromDomain,\n Type: \"TXT\",\n TTL: 1800,\n ResourceRecords: [{ Value: '\"v=spf1 include:amazonses.com ~all\"' }],\n },\n });\n }\n\n if (changes.length === 0) {\n return; // Nothing to create\n }\n\n await client.send(\n new ChangeResourceRecordSetsCommand({\n HostedZoneId: hostedZoneId,\n ChangeBatch: {\n Changes: changes,\n },\n })\n );\n}\n\n/**\n * Find Route53 hosted zone for a domain\n */\nexport async function findHostedZone(\n domain: string,\n region: string\n): Promise<{ id: string; name: string } | null> {\n const client = new Route53Client({ region });\n\n try {\n const response = await client.send(\n new ListHostedZonesByNameCommand({\n DNSName: domain,\n MaxItems: 1,\n })\n );\n\n const zone = response.HostedZones?.[0];\n if (zone && zone.Name === `${domain}.` && zone.Id) {\n return {\n id: zone.Id.replace(\"/hostedzone/\", \"\"),\n name: zone.Name,\n };\n }\n\n return null;\n } catch (_error) {\n return null;\n }\n}\n\n/**\n * Create DNS records in Route53\n */\nexport async function createDNSRecords(\n hostedZoneId: string,\n domain: string,\n dkimTokens: string[],\n region: string,\n customTrackingDomain?: string,\n mailFromDomain?: string,\n cloudFrontDomain?: string\n): Promise<void> {\n const client = new Route53Client({ region });\n\n const changes: Change[] = [];\n\n // DKIM CNAME records\n for (const token of dkimTokens) {\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: `${token}._domainkey.${domain}`,\n Type: \"CNAME\",\n TTL: 1800,\n ResourceRecords: [{ Value: `${token}.dkim.amazonses.com` }],\n },\n });\n }\n\n // SPF TXT record - check for existing records and merge while preserving others\n const existingTXT = await getExistingTXTRecords(client, hostedZoneId, domain);\n\n // Build the new TXT record values, preserving all non-SPF records\n const newTXTValues: string[] = [];\n\n if (existingTXT.spfValue) {\n // Merge our include into the existing SPF record\n const mergedSPF = mergeSPFRecord(existingTXT.spfValue);\n newTXTValues.push(`\"${mergedSPF}\"`);\n\n // Add all other TXT values (non-SPF)\n for (const value of existingTXT.allValues) {\n const unquoted = value.replace(/^\"|\"$/g, \"\");\n if (!unquoted.startsWith(\"v=spf1\")) {\n newTXTValues.push(value);\n }\n }\n } else if (existingTXT.allValues.length > 0) {\n // No SPF exists, add new SPF and keep all existing values\n newTXTValues.push('\"v=spf1 include:amazonses.com ~all\"');\n newTXTValues.push(...existingTXT.allValues);\n } else {\n // No TXT records exist, create new SPF\n newTXTValues.push('\"v=spf1 include:amazonses.com ~all\"');\n }\n\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: domain,\n Type: \"TXT\",\n TTL: existingTXT.ttl,\n ResourceRecords: newTXTValues.map((v) => ({ Value: v })),\n },\n });\n\n // DMARC TXT record\n // Use MAIL FROM domain for rua if configured, otherwise use main domain\n const dmarcRuaDomain = mailFromDomain || domain;\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: `_dmarc.${domain}`,\n Type: \"TXT\",\n TTL: 1800,\n ResourceRecords: [\n {\n Value: `\"v=DMARC1; p=quarantine; rua=mailto:postmaster@${dmarcRuaDomain}\"`,\n },\n ],\n },\n });\n\n // Custom tracking domain CNAME (if provided)\n // This allows SES to rewrite links for open/click tracking using your custom domain\n if (customTrackingDomain) {\n // If CloudFront domain is provided, use it (HTTPS tracking)\n // Otherwise, use direct SES tracking endpoint (HTTP tracking)\n const targetDomain = cloudFrontDomain || `r.${region}.awstrack.me`;\n\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: customTrackingDomain,\n Type: \"CNAME\",\n TTL: 1800,\n ResourceRecords: [{ Value: targetDomain }],\n },\n });\n }\n\n // MAIL FROM domain records (if provided)\n // These records enable DMARC alignment by using a custom subdomain for the envelope sender\n if (mailFromDomain) {\n // MX record pointing to SES feedback server\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: mailFromDomain,\n Type: \"MX\",\n TTL: 1800,\n ResourceRecords: [\n { Value: `10 feedback-smtp.${region}.amazonses.com` },\n ],\n },\n });\n\n // SPF record for MAIL FROM domain\n changes.push({\n Action: \"UPSERT\",\n ResourceRecordSet: {\n Name: mailFromDomain,\n Type: \"TXT\",\n TTL: 1800,\n ResourceRecords: [{ Value: '\"v=spf1 include:amazonses.com ~all\"' }],\n },\n });\n }\n\n await client.send(\n new ChangeResourceRecordSetsCommand({\n HostedZoneId: hostedZoneId,\n ChangeBatch: {\n Changes: changes,\n },\n })\n );\n}\n\n/**\n * Delete DNS records from Route53 that were created for SES\n */\nexport async function deleteDNSRecords(\n hostedZoneId: string,\n domain: string,\n dkimTokens: string[],\n region: string,\n customTrackingDomain?: string,\n mailFromDomain?: string\n): Promise<void> {\n const client = new Route53Client({ region });\n\n // First, we need to get the current record values to delete them\n // Route53 DELETE requires exact match of the record\n const response = await client.send(\n new ListResourceRecordSetsCommand({\n HostedZoneId: hostedZoneId,\n MaxItems: 500,\n })\n );\n\n const recordSets = response.ResourceRecordSets || [];\n const changes: Change[] = [];\n\n // Helper to find and add deletion for a record\n const addDeletionIfExists = (name: string, type: string) => {\n // Route53 names end with a dot\n const normalizedName = name.endsWith(\".\") ? name : `${name}.`;\n const record = recordSets.find(\n (rs) => rs.Name === normalizedName && rs.Type === type\n );\n if (record?.ResourceRecords) {\n changes.push({\n Action: \"DELETE\",\n ResourceRecordSet: record,\n });\n }\n };\n\n // DKIM CNAME records\n for (const token of dkimTokens) {\n addDeletionIfExists(`${token}._domainkey.${domain}`, \"CNAME\");\n }\n\n // DMARC record\n addDeletionIfExists(`_dmarc.${domain}`, \"TXT\");\n\n // Custom tracking domain CNAME\n if (customTrackingDomain) {\n addDeletionIfExists(customTrackingDomain, \"CNAME\");\n }\n\n // MAIL FROM domain records\n if (mailFromDomain) {\n addDeletionIfExists(mailFromDomain, \"MX\");\n addDeletionIfExists(mailFromDomain, \"TXT\");\n }\n\n // Note: We don't delete the main domain SPF record as it might contain\n // other providers' includes. Users should manually remove amazonses.com\n // from their SPF if needed.\n\n if (changes.length === 0) {\n return; // Nothing to delete\n }\n\n await client.send(\n new ChangeResourceRecordSetsCommand({\n HostedZoneId: hostedZoneId,\n ChangeBatch: {\n Changes: changes,\n },\n })\n );\n}\n","import * as aws from \"@pulumi/aws\";\nimport type * as pulumi from \"@pulumi/pulumi\";\n\n/**\n * ACM certificate configuration\n */\nexport type ACMCertificateConfig = {\n domain: string;\n hostedZoneId?: string; // Optional Route53 hosted zone for automatic DNS validation\n};\n\n/**\n * ACM certificate output\n */\nexport type ACMCertificateResources = {\n certificate: aws.acm.Certificate;\n certificateValidation?: aws.acm.CertificateValidation;\n validationRecords: pulumi.Output<\n Array<{\n name: string;\n type: string;\n value: string;\n }>\n >;\n};\n\n/**\n * Create ACM certificate for custom tracking domain\n *\n * IMPORTANT: CloudFront requires ACM certificates to be created in us-east-1 region.\n * This function creates the certificate in us-east-1 regardless of the SES region.\n *\n * If a Route53 hosted zone ID is provided, DNS validation records will be created\n * automatically and we'll wait for validation. Otherwise, validation records are\n * returned for manual creation.\n */\nexport async function createACMCertificate(\n config: ACMCertificateConfig\n): Promise<ACMCertificateResources> {\n const usEast1Provider = new aws.Provider(\"acm-us-east-1\", {\n region: \"us-east-1\",\n });\n\n // Create ACM certificate in us-east-1 (required for CloudFront)\n const certificate = new aws.acm.Certificate(\n \"wraps-email-tracking-cert\",\n {\n domainName: config.domain,\n validationMethod: \"DNS\",\n tags: {\n ManagedBy: \"wraps-cli\",\n Description: \"SSL certificate for Wraps email tracking domain\",\n },\n },\n {\n provider: usEast1Provider,\n }\n );\n\n // Extract validation records\n const validationRecords = certificate.domainValidationOptions.apply(\n (options) =>\n options.map((option) => ({\n name: option.resourceRecordName,\n type: option.resourceRecordType,\n value: option.resourceRecordValue,\n }))\n );\n\n // If Route53 hosted zone is provided, create validation records automatically\n let certificateValidation: aws.acm.CertificateValidation | undefined;\n\n if (config.hostedZoneId) {\n // Create validation record in Route53\n const validationRecord = new aws.route53.Record(\n \"wraps-email-tracking-cert-validation\",\n {\n zoneId: config.hostedZoneId,\n name: certificate.domainValidationOptions[0].resourceRecordName,\n type: certificate.domainValidationOptions[0].resourceRecordType,\n records: [certificate.domainValidationOptions[0].resourceRecordValue],\n ttl: 60,\n }\n );\n\n // Wait for certificate validation to complete\n certificateValidation = new aws.acm.CertificateValidation(\n \"wraps-email-tracking-cert-validation-waiter\",\n {\n certificateArn: certificate.arn,\n validationRecordFqdns: [validationRecord.fqdn],\n },\n {\n provider: usEast1Provider,\n }\n );\n }\n // For manual DNS: certificateValidation is undefined\n // User must add DNS records manually and run upgrade again\n\n return {\n certificate,\n certificateValidation,\n validationRecords,\n };\n}\n","import * as aws from \"@pulumi/aws\";\nimport type * as pulumi from \"@pulumi/pulumi\";\n\n/**\n * CloudFront resources configuration\n */\nexport type CloudFrontTrackingConfig = {\n customTrackingDomain: string;\n region: string; // SES region for the origin\n certificateArn: pulumi.Output<string>;\n hostedZoneId?: string; // Optional Route53 hosted zone for automatic DNS record creation\n};\n\n/**\n * Find existing CloudFront distribution by alias (CNAME)\n */\nasync function findDistributionByAlias(alias: string): Promise<string | null> {\n try {\n const { CloudFrontClient, ListDistributionsCommand } = await import(\n \"@aws-sdk/client-cloudfront\"\n );\n const cloudfront = new CloudFrontClient({ region: \"us-east-1\" }); // CloudFront is global but API is in us-east-1\n\n const response = await cloudfront.send(new ListDistributionsCommand({}));\n\n // Find distribution with matching alias\n const distribution = response.DistributionList?.Items?.find((dist) =>\n dist.Aliases?.Items?.includes(alias)\n );\n\n return distribution?.Id || null;\n } catch (error) {\n console.error(\"Error finding CloudFront distribution:\", error);\n return null;\n }\n}\n\n/**\n * CloudFront resources output\n */\nexport type CloudFrontResources = {\n distribution: aws.cloudfront.Distribution;\n domainName: pulumi.Output<string>;\n webAcl: aws.wafv2.WebAcl;\n};\n\n/**\n * Create WAF Web ACL with rate limiting for CloudFront\n *\n * This creates a WAFv2 Web ACL with rate limiting protection\n * to prevent abuse of tracking endpoints.\n */\nasync function createWAFWebACL(): Promise<aws.wafv2.WebAcl> {\n // WAF for CloudFront must be created in us-east-1\n const usEast1Provider = new aws.Provider(\"waf-us-east-1\", {\n region: \"us-east-1\",\n });\n\n const webAcl = new aws.wafv2.WebAcl(\n \"wraps-email-tracking-waf\",\n {\n scope: \"CLOUDFRONT\", // WAF for CloudFront must use CLOUDFRONT scope\n description: \"Rate limiting protection for Wraps email tracking\",\n\n defaultAction: {\n allow: {}, // Allow by default\n },\n\n rules: [\n {\n name: \"RateLimitRule\",\n priority: 1,\n action: {\n block: {}, // Block requests exceeding rate limit\n },\n statement: {\n rateBasedStatement: {\n limit: 2000, // 2000 requests per 5 minutes per IP\n aggregateKeyType: \"IP\",\n },\n },\n visibilityConfig: {\n sampledRequestsEnabled: true,\n cloudwatchMetricsEnabled: true,\n metricName: \"RateLimitRule\",\n },\n },\n ],\n\n visibilityConfig: {\n sampledRequestsEnabled: true,\n cloudwatchMetricsEnabled: true,\n metricName: \"wraps-email-tracking-waf\",\n },\n\n tags: {\n ManagedBy: \"wraps-cli\",\n Description: \"WAF for Wraps email tracking with rate limiting\",\n },\n },\n {\n provider: usEast1Provider,\n }\n );\n\n return webAcl;\n}\n\n/**\n * Create CloudFront distribution for HTTPS tracking domain\n *\n * This creates a CloudFront distribution that sits in front of AWS SES's tracking endpoint\n * (r.{region}.awstrack.me) and provides HTTPS support with a custom domain and SSL certificate.\n * Also creates a WAF Web ACL with rate limiting for security.\n */\nexport async function createCloudFrontTracking(\n config: CloudFrontTrackingConfig\n): Promise<CloudFrontResources> {\n const sesTrackingOrigin = `r.${config.region}.awstrack.me`;\n\n // Create WAF Web ACL with rate limiting protection\n const webAcl = await createWAFWebACL();\n\n // Check if CloudFront distribution already exists with this alias\n const existingDistributionId = await findDistributionByAlias(\n config.customTrackingDomain\n );\n\n // CloudFront distribution configuration\n const distributionConfig = {\n enabled: true,\n comment: \"Wraps email tracking with HTTPS support\",\n aliases: [config.customTrackingDomain],\n\n // Attach WAF Web ACL for rate limiting protection\n webAclId: webAcl.arn,\n\n // Origin: SES tracking endpoint\n origins: [\n {\n domainName: sesTrackingOrigin,\n originId: \"ses-tracking\",\n customOriginConfig: {\n httpPort: 80,\n httpsPort: 443,\n originProtocolPolicy: \"http-only\", // SES tracking endpoint is HTTP\n originSslProtocols: [\"TLSv1.2\"],\n },\n },\n ],\n\n // Default cache behavior\n defaultCacheBehavior: {\n targetOriginId: \"ses-tracking\",\n viewerProtocolPolicy: \"redirect-to-https\", // Force HTTPS\n allowedMethods: [\"GET\", \"HEAD\", \"OPTIONS\"],\n cachedMethods: [\"GET\", \"HEAD\"],\n\n // Forward all query strings and headers (tracking links use query params)\n forwardedValues: {\n queryString: true,\n cookies: {\n forward: \"all\",\n },\n headers: [\"*\"], // Forward all headers to preserve tracking functionality\n },\n\n // Minimal caching for tracking redirects\n minTtl: 0,\n defaultTtl: 0,\n maxTtl: 31_536_000,\n\n compress: true,\n },\n\n // Price class (use only North America & Europe for cost optimization)\n priceClass: \"PriceClass_100\",\n\n // Restrictions (none)\n restrictions: {\n geoRestriction: {\n restrictionType: \"none\",\n },\n },\n\n // SSL certificate from ACM\n viewerCertificate: {\n acmCertificateArn: config.certificateArn,\n sslSupportMethod: \"sni-only\",\n minimumProtocolVersion: \"TLSv1.2_2021\",\n },\n\n tags: {\n ManagedBy: \"wraps-cli\",\n Description: \"Wraps email tracking CloudFront distribution\",\n },\n };\n\n const distribution = existingDistributionId\n ? new aws.cloudfront.Distribution(\n \"wraps-email-tracking-cdn\",\n distributionConfig,\n {\n import: existingDistributionId, // Import existing distribution\n }\n )\n : new aws.cloudfront.Distribution(\n \"wraps-email-tracking-cdn\",\n distributionConfig\n );\n\n // Note: DNS CNAME record for custom tracking domain is created separately\n // via Route53 SDK in route53.ts (using UPSERT for idempotency)\n // This prevents Pulumi resource conflicts on subsequent deployments\n\n return {\n distribution,\n domainName: distribution.domainName,\n webAcl,\n };\n}\n","import {\n CreateArchiveCommand,\n GetArchiveCommand,\n ListArchivesCommand,\n MailManagerClient,\n type RetentionPeriod,\n} from \"@aws-sdk/client-mailmanager\";\nimport {\n PutConfigurationSetArchivingOptionsCommand,\n SESv2Client,\n} from \"@aws-sdk/client-sesv2\";\nimport type * as pulumi from \"@pulumi/pulumi\";\nimport type { ArchiveRetention } from \"../../types/index.js\";\n\n/**\n * Mail Manager archive configuration\n */\nexport type MailManagerArchiveConfig = {\n name: string;\n retention: ArchiveRetention;\n configSetName: pulumi.Output<string>;\n region?: string;\n kmsKeyArn?: string; // Optional: provide existing KMS key, otherwise AWS-managed key is used\n};\n\n/**\n * Mail Manager archive resources\n */\nexport type MailManagerArchiveResources = {\n archiveId: string;\n archiveArn: string;\n kmsKeyArn?: string;\n};\n\n/**\n * Convert our retention types to AWS SDK RetentionPeriod enum\n */\nfunction retentionToAWSPeriod(retention: ArchiveRetention): RetentionPeriod {\n switch (retention) {\n case \"3months\":\n return \"THREE_MONTHS\";\n case \"6months\":\n return \"SIX_MONTHS\";\n case \"9months\":\n return \"NINE_MONTHS\";\n case \"1year\":\n return \"ONE_YEAR\";\n case \"18months\":\n return \"EIGHTEEN_MONTHS\";\n case \"2years\":\n return \"TWO_YEARS\";\n case \"30months\":\n return \"THIRTY_MONTHS\";\n case \"3years\":\n return \"THREE_YEARS\";\n case \"4years\":\n return \"FOUR_YEARS\";\n case \"5years\":\n return \"FIVE_YEARS\";\n case \"6years\":\n return \"SIX_YEARS\";\n case \"7years\":\n return \"SEVEN_YEARS\";\n case \"8years\":\n return \"EIGHT_YEARS\";\n case \"9years\":\n return \"NINE_YEARS\";\n case \"10years\":\n return \"TEN_YEARS\";\n case \"permanent\":\n return \"PERMANENT\";\n default:\n return \"THREE_MONTHS\";\n }\n}\n\n/**\n * Create Mail Manager archive for storing full email content\n *\n * This creates:\n * 1. Mail Manager Archive - stores RFC 822/MIME formatted emails\n * 2. Links archive to SES Configuration Set\n *\n * Uses AWS SDK directly since Pulumi doesn't support Mail Manager yet.\n *\n * Cost: $2/GB ingestion + $0.19/GB/month storage\n * See: https://docs.aws.amazon.com/ses/latest/dg/eb-archiving.html\n *\n * Note: KMS encryption is optional. If not provided, AWS-managed encryption is used.\n */\nexport async function createMailManagerArchive(\n config: MailManagerArchiveConfig\n): Promise<MailManagerArchiveResources> {\n const region = config.region || process.env.AWS_REGION || \"us-east-1\";\n const archiveName = `wraps-${config.name}-archive`;\n\n // Initialize clients\n const mailManagerClient = new MailManagerClient({ region });\n const sesClient = new SESv2Client({ region });\n\n const kmsKeyArn = config.kmsKeyArn;\n\n // If no KMS key provided, create one for encryption\n // Note: User can also opt to not provide one and AWS will use service-managed keys\n if (!kmsKeyArn) {\n // For now, we'll let AWS use service-managed keys\n // In the future, we could create a customer-managed key here if needed:\n //\n // const kmsClient = new KMSClient({ region });\n // const createKeyResult = await kmsClient.send(\n // new CreateKeyCommand({\n // Description: `KMS key for Wraps email archive (${archiveName})`,\n // Tags: [\n // { TagKey: \"ManagedBy\", TagValue: \"wraps-cli\" },\n // { TagKey: \"Name\", TagValue: `wraps-${config.name}-archive-key` },\n // ],\n // })\n // );\n // kmsKeyArn = createKeyResult.KeyMetadata?.Arn;\n }\n\n // 1. Create Mail Manager Archive (or get existing)\n const awsRetention = retentionToAWSPeriod(config.retention);\n\n let archiveId: string | undefined;\n let archiveArn: string | undefined;\n\n // Check if archive already exists\n try {\n const listCommand = new ListArchivesCommand({});\n const listResult = await mailManagerClient.send(listCommand);\n\n const existingArchive = listResult.Archives?.find(\n (archive: { ArchiveName?: string; ArchiveId?: string }) =>\n archive.ArchiveName === archiveName\n );\n\n if (existingArchive?.ArchiveId) {\n // Archive exists, use it\n console.log(`Using existing Mail Manager archive: ${archiveName}`);\n archiveId = existingArchive.ArchiveId;\n\n // Get full archive details to get ARN\n const getCommand = new GetArchiveCommand({ ArchiveId: archiveId });\n const getResult = await mailManagerClient.send(getCommand);\n archiveArn = getResult.ArchiveArn;\n }\n } catch (error) {\n console.log(\"Error checking for existing archive:\", error);\n // Continue to create new archive\n }\n\n // Create archive if it doesn't exist\n if (!archiveId) {\n try {\n const createArchiveCommand = new CreateArchiveCommand({\n ArchiveName: archiveName,\n Retention: {\n RetentionPeriod: awsRetention,\n },\n ...(kmsKeyArn && { KmsKeyArn: kmsKeyArn }),\n Tags: [\n { Key: \"ManagedBy\", Value: \"wraps-cli\" },\n { Key: \"Name\", Value: archiveName },\n { Key: \"Retention\", Value: config.retention },\n ],\n });\n\n const archiveResult = await mailManagerClient.send(createArchiveCommand);\n archiveId = archiveResult.ArchiveId;\n\n if (!archiveId) {\n throw new Error(\n \"Failed to create Mail Manager Archive: No ArchiveId returned\"\n );\n }\n\n console.log(`Created new Mail Manager archive: ${archiveName}`);\n } catch (error) {\n // If it's a ConflictException, the archive was created between our check and now\n if (\n error instanceof Error &&\n error.name === \"ConflictException\" &&\n error.message.includes(\"Archive already exists\")\n ) {\n console.log(\n \"Archive was created concurrently, fetching existing archive...\"\n );\n\n // List again and find it\n const listCommand = new ListArchivesCommand({});\n const listResult = await mailManagerClient.send(listCommand);\n const existingArchive = listResult.Archives?.find(\n (archive: { ArchiveName?: string; ArchiveId?: string }) =>\n archive.ArchiveName === archiveName\n );\n\n if (!existingArchive?.ArchiveId) {\n throw new Error(\n `Archive exists but couldn't find it: ${archiveName}`\n );\n }\n\n archiveId = existingArchive.ArchiveId;\n\n // Get full archive details\n const getCommand = new GetArchiveCommand({ ArchiveId: archiveId });\n const getResult = await mailManagerClient.send(getCommand);\n archiveArn = getResult.ArchiveArn;\n } else {\n throw error;\n }\n }\n }\n\n // Construct the ARN if we don't have it yet\n if (!archiveArn) {\n // ARN format: arn:aws:ses:region:account-id:mailmanager-archive/archive-id\n const identity = await import(\"@aws-sdk/client-sts\").then((m) =>\n new m.STSClient({ region }).send(new m.GetCallerIdentityCommand({}))\n );\n const accountId = identity.Account;\n archiveArn = `arn:aws:ses:${region}:${accountId}:mailmanager-archive/${archiveId}`;\n }\n\n // 2. Link archive to SES Configuration Set\n // We need to wait for the configSetName to resolve from Pulumi Output\n const configSetName = await new Promise<string>((resolve) => {\n config.configSetName.apply((name) => {\n resolve(name);\n });\n });\n\n const putArchivingOptionsCommand =\n new PutConfigurationSetArchivingOptionsCommand({\n ConfigurationSetName: configSetName,\n ArchiveArn: archiveArn,\n });\n\n await sesClient.send(putArchivingOptionsCommand);\n\n if (!(archiveId && archiveArn)) {\n throw new Error(\"Failed to get archive ID or ARN\");\n }\n\n return {\n archiveId,\n archiveArn,\n kmsKeyArn,\n };\n}\n","import type {\n ArchiveRetention,\n FeatureCost,\n FeatureCostBreakdown,\n WrapsEmailConfig,\n} from \"../../types/index.js\";\n\n/**\n * AWS pricing constants (as of 2025)\n * All costs in USD (US East N. Virginia region)\n * Source: aws.amazon.com pricing pages verified January 2025\n */\nconst AWS_PRICING = {\n // SES pricing\n SES_PER_EMAIL: 0.0001, // $0.10 per 1,000 emails (outbound)\n SES_ATTACHMENT_PER_GB: 0.12, // $0.12 per GB of attachments\n\n // DynamoDB pricing (on-demand, Standard table class)\n DYNAMODB_WRITE_PER_MILLION: 1.25, // $1.25 per million write request units (US East Ohio)\n DYNAMODB_READ_PER_MILLION: 0.25, // $0.25 per million read request units (US East Ohio)\n DYNAMODB_STORAGE_PER_GB: 0.25, // $0.25 per GB-month\n\n // Lambda pricing (x86)\n LAMBDA_REQUESTS_PER_MILLION: 0.2, // $0.20 per 1M requests\n LAMBDA_COMPUTE_PER_GB_SECOND: 0.000_016_666_7, // $0.0000166667 per GB-second\n\n // SQS pricing (Standard queues)\n SQS_REQUESTS_PER_MILLION: 0.5, // $0.50 per million requests (after free tier)\n\n // EventBridge pricing\n EVENTBRIDGE_EVENTS_PER_MILLION: 1.0, // $1.00 per million custom events published\n\n // Dedicated IP\n DEDICATED_IP_PER_MONTH: 24.95, // $24.95 per dedicated IP per month\n\n // CloudWatch pricing\n CLOUDWATCH_LOGS_PER_GB: 0.5, // $0.50 per GB ingested\n CLOUDWATCH_LOGS_STORAGE_PER_GB: 0.03, // $0.03 per GB-month\n\n // SES Mail Manager Archiving\n MAIL_MANAGER_INGESTION_PER_GB: 2.0, // $2.00 per GB ingested\n MAIL_MANAGER_STORAGE_PER_GB: 0.19, // $0.19 per GB-month\n} as const;\n\n/**\n * AWS Free tier limits (monthly, always-free or first 12 months)\n * Note: Some limits are permanently free, others only for first 12 months\n */\nconst FREE_TIER = {\n // SES: 3,000 emails/month for first 12 months (new AWS accounts only)\n // After 12 months or for existing accounts: NO free tier\n SES_EMAILS: 0, // Conservative: assume no free tier (most users are past 12 months)\n\n // Lambda: Permanently free tier\n LAMBDA_REQUESTS: 1_000_000, // 1M requests per month (always free)\n LAMBDA_COMPUTE_GB_SECONDS: 400_000, // 400,000 GB-seconds per month (always free)\n\n // DynamoDB: Permanently free tier\n DYNAMODB_WRITES: 0, // No free tier for writes in on-demand mode\n DYNAMODB_READS: 0, // No free tier for reads in on-demand mode\n DYNAMODB_STORAGE_GB: 25, // 25 GB storage per month (always free)\n\n // SQS: Permanently free tier\n SQS_REQUESTS: 1_000_000, // 1M requests per month (always free)\n\n // CloudWatch: Permanently free tier\n CLOUDWATCH_LOGS_GB: 5, // 5 GB ingestion per month (always free)\n} as const;\n\n/**\n * Estimate storage size in GB based on retention period and email volume\n * Note: Each email generates multiple events (SEND, DELIVERY, OPEN, CLICK, etc.)\n *\n * This calculates STEADY-STATE storage (after retention period fills up).\n * Initial months will be cheaper as storage builds up gradually.\n *\n * Example for 90-day retention with 10k emails/month:\n * - Month 1: ~0.015 GB stored\n * - Month 2: ~0.031 GB stored\n * - Month 3: ~0.046 GB stored (steady state reached)\n * - Month 4+: ~0.046 GB stored (old data deleted, new data added)\n */\nfunction estimateStorageSize(\n emailsPerMonth: number,\n retention: ArchiveRetention,\n numEventTypes = 8\n): number {\n // Average email event record size: ~2 KB (including metadata)\n const avgRecordSizeKB = 2;\n\n // Calculate total months of retention\n const retentionMonths = {\n \"7days\": 0.25,\n \"30days\": 1,\n \"90days\": 3,\n \"3months\": 3,\n \"6months\": 6,\n \"9months\": 9,\n \"1year\": 12,\n \"18months\": 18,\n \"2years\": 24,\n \"30months\": 30,\n \"3years\": 36,\n \"4years\": 48,\n \"5years\": 60,\n \"6years\": 72,\n \"7years\": 84,\n \"8years\": 96,\n \"9years\": 108,\n \"10years\": 120,\n indefinite: 120,\n permanent: 120,\n }[retention];\n\n // Total steady-state storage = emails/month * event types * months * record size\n // This represents storage after retention period fills up\n const totalKB =\n emailsPerMonth * numEventTypes * (retentionMonths ?? 12) * avgRecordSizeKB;\n return totalKB / 1024 / 1024; // Convert to GB\n}\n\n/**\n * Estimate email archive storage size in GB (for full email content)\n * Different from event storage - stores complete RFC 822/MIME emails\n *\n * This calculates STEADY-STATE storage (after retention period fills up).\n */\nfunction estimateArchiveStorageSize(\n emailsPerMonth: number,\n retention: ArchiveRetention\n): number {\n // Average full email size: ~50 KB (HTML, headers, small attachments)\n const avgEmailSizeKB = 50;\n\n // Calculate total months of retention\n const retentionMonths = {\n \"7days\": 0.25,\n \"30days\": 1,\n \"90days\": 3,\n \"3months\": 3,\n \"6months\": 6,\n \"9months\": 9,\n \"1year\": 12,\n \"18months\": 18,\n \"2years\": 24,\n \"30months\": 30,\n \"3years\": 36,\n \"4years\": 48,\n \"5years\": 60,\n \"6years\": 72,\n \"7years\": 84,\n \"8years\": 96,\n \"9years\": 108,\n \"10years\": 120,\n indefinite: 120,\n permanent: 120,\n }[retention];\n\n // Total steady-state storage = emails/month * months * email size\n const totalKB = emailsPerMonth * (retentionMonths ?? 12) * avgEmailSizeKB;\n return totalKB / 1024 / 1024; // Convert to GB\n}\n\n/**\n * Calculate cost for event tracking feature\n * Architecture: SES → EventBridge → SQS → Lambda → DynamoDB\n */\nfunction calculateEventTrackingCost(\n config: WrapsEmailConfig,\n emailsPerMonth: number\n): FeatureCost | undefined {\n if (!config.eventTracking?.enabled) {\n return;\n }\n\n let monthlyCost = 0;\n const components: string[] = [];\n\n // Calculate number of events based on event types tracked\n const numEventTypes = config.eventTracking.events?.length || 8; // Default to 8 common events\n const totalEvents = emailsPerMonth * numEventTypes; // Each email can trigger multiple events\n\n // EventBridge custom events (SES → EventBridge)\n if (config.eventTracking.eventBridge) {\n const eventCost =\n (totalEvents / 1_000_000) * AWS_PRICING.EVENTBRIDGE_EVENTS_PER_MILLION;\n monthlyCost += eventCost;\n components.push(\"EventBridge\");\n }\n\n // SQS queue costs (EventBridge → SQS)\n // Each event: 1 send to SQS + 1 receive by Lambda + 1 delete = 3 requests\n const sqsRequests = totalEvents * 3;\n const sqsCost =\n (Math.max(0, sqsRequests - FREE_TIER.SQS_REQUESTS) / 1_000_000) *\n AWS_PRICING.SQS_REQUESTS_PER_MILLION;\n monthlyCost += sqsCost;\n components.push(\"SQS\");\n\n // Lambda processing costs (SQS → Lambda → DynamoDB)\n const lambdaInvocations = totalEvents; // One invocation per event\n const lambdaRequestCost =\n (Math.max(0, lambdaInvocations - FREE_TIER.LAMBDA_REQUESTS) / 1_000_000) *\n AWS_PRICING.LAMBDA_REQUESTS_PER_MILLION;\n\n // Compute cost: 512MB memory, 100ms average execution\n const memoryGB = 0.5; // 512MB = 0.5GB\n const avgDurationSeconds = 0.1; // 100ms\n const computeGBSeconds = lambdaInvocations * memoryGB * avgDurationSeconds;\n const lambdaComputeCost =\n Math.max(0, computeGBSeconds - FREE_TIER.LAMBDA_COMPUTE_GB_SECONDS) *\n AWS_PRICING.LAMBDA_COMPUTE_PER_GB_SECOND;\n\n monthlyCost += lambdaRequestCost + lambdaComputeCost;\n components.push(\"Lambda\");\n\n return {\n monthly: monthlyCost,\n description: `Event processing (${numEventTypes} event types: ${components.join(\" → \")})`,\n };\n}\n\n/**\n * Calculate cost for DynamoDB email history storage\n */\nfunction calculateDynamoDBCost(\n config: WrapsEmailConfig,\n emailsPerMonth: number\n): FeatureCost | undefined {\n if (!config.eventTracking?.dynamoDBHistory) {\n return;\n }\n\n const retention = config.eventTracking.archiveRetention || \"90days\";\n const numEventTypes = config.eventTracking.events?.length || 8;\n\n // Write costs: one write per event (each email generates multiple events)\n const totalEvents = emailsPerMonth * numEventTypes;\n const writeCost =\n (Math.max(0, totalEvents - FREE_TIER.DYNAMODB_WRITES) / 1_000_000) *\n AWS_PRICING.DYNAMODB_WRITE_PER_MILLION;\n\n // Storage costs\n const storageGB = estimateStorageSize(\n emailsPerMonth,\n retention,\n numEventTypes\n );\n const storageCost =\n Math.max(0, storageGB - FREE_TIER.DYNAMODB_STORAGE_GB) *\n AWS_PRICING.DYNAMODB_STORAGE_PER_GB;\n\n return {\n monthly: writeCost + storageCost,\n description: `Email history (${retention}, ~${storageGB.toFixed(2)} GB at steady-state, ${numEventTypes} event types)`,\n };\n}\n\n/**\n * Calculate cost for tracking features (opens/clicks)\n */\nfunction calculateTrackingCost(\n config: WrapsEmailConfig\n): FeatureCost | undefined {\n if (!config.tracking?.enabled) {\n return;\n }\n\n // Tracking is free - it's built into SES\n // Custom redirect domain DNS records are managed where user already manages DNS\n return {\n monthly: 0,\n description: \"Open/click tracking (no additional cost)\",\n };\n}\n\n/**\n * Calculate cost for reputation metrics\n */\nfunction calculateReputationMetricsCost(\n config: WrapsEmailConfig\n): FeatureCost | undefined {\n if (!config.reputationMetrics) {\n return;\n }\n\n // Reputation metrics are free in CloudWatch\n return {\n monthly: 0,\n description: \"Reputation metrics in CloudWatch (no additional cost)\",\n };\n}\n\n/**\n * Calculate cost for dedicated IP\n */\nfunction calculateDedicatedIpCost(\n config: WrapsEmailConfig\n): FeatureCost | undefined {\n if (!config.dedicatedIp) {\n return;\n }\n\n return {\n monthly: AWS_PRICING.DEDICATED_IP_PER_MONTH,\n description: \"Dedicated IP address (requires 100k+ emails/day for warmup)\",\n };\n}\n\n/**\n * Calculate cost for email archiving (full email content storage)\n * Architecture: SES → Mail Manager Archive (S3-backed)\n */\nfunction calculateEmailArchivingCost(\n config: WrapsEmailConfig,\n emailsPerMonth: number\n): FeatureCost | undefined {\n if (!config.emailArchiving?.enabled) {\n return;\n }\n\n const retention = config.emailArchiving.retention;\n const storageGB = estimateArchiveStorageSize(emailsPerMonth, retention);\n\n // Ingestion cost: one-time per email (charged monthly as new emails arrive)\n const monthlyDataGB = (emailsPerMonth * 50) / 1024 / 1024; // 50 KB average email\n const ingestionCost =\n monthlyDataGB * AWS_PRICING.MAIL_MANAGER_INGESTION_PER_GB;\n\n // Storage cost: steady-state storage after retention period fills\n const storageCost = storageGB * AWS_PRICING.MAIL_MANAGER_STORAGE_PER_GB;\n\n return {\n monthly: ingestionCost + storageCost,\n description: `Email archiving (${retention}, ~${storageGB.toFixed(2)} GB at steady-state)`,\n };\n}\n\n/**\n * Calculate total infrastructure costs\n *\n * @param config Email configuration\n * @param emailsPerMonth Estimated monthly email volume\n * @returns Detailed cost breakdown\n */\nexport function calculateCosts(\n config: WrapsEmailConfig,\n emailsPerMonth = 10_000\n): FeatureCostBreakdown {\n const tracking = calculateTrackingCost(config);\n const reputationMetrics = calculateReputationMetricsCost(config);\n const eventTracking = calculateEventTrackingCost(config, emailsPerMonth);\n const dynamoDBHistory = calculateDynamoDBCost(config, emailsPerMonth);\n const emailArchiving = calculateEmailArchivingCost(config, emailsPerMonth);\n const dedicatedIp = calculateDedicatedIpCost(config);\n\n // Calculate SES base costs (always present)\n const sesEmailCost =\n Math.max(0, emailsPerMonth - FREE_TIER.SES_EMAILS) *\n AWS_PRICING.SES_PER_EMAIL;\n\n // Sum all costs\n const totalMonthlyCost =\n sesEmailCost +\n (tracking?.monthly || 0) +\n (reputationMetrics?.monthly || 0) +\n (eventTracking?.monthly || 0) +\n (dynamoDBHistory?.monthly || 0) +\n (emailArchiving?.monthly || 0) +\n (dedicatedIp?.monthly || 0);\n\n return {\n tracking,\n reputationMetrics,\n eventTracking,\n dynamoDBHistory,\n emailArchiving,\n dedicatedIp,\n total: {\n monthly: totalMonthlyCost,\n perEmail: AWS_PRICING.SES_PER_EMAIL,\n description: `Total estimated cost for ${emailsPerMonth.toLocaleString()} emails/month`,\n },\n };\n}\n\n/**\n * Format cost for display\n */\nexport function formatCost(cost: number): string {\n if (cost === 0) {\n return \"Free\";\n }\n if (cost < 0.01) {\n return \"< $0.01\";\n }\n return `$${cost.toFixed(2)}`;\n}\n\n/**\n * Get cost estimate summary for display\n */\nexport function getCostSummary(\n config: WrapsEmailConfig,\n emailsPerMonth = 10_000\n): string {\n const costs = calculateCosts(config, emailsPerMonth);\n const lines: string[] = [];\n\n lines.push(\n `Estimated cost for ${emailsPerMonth.toLocaleString()} emails/month: ${formatCost(costs.total.monthly)}/mo`\n );\n lines.push(\n ` (${formatCost((costs.total.perEmail ?? 0) * 1000)}/1k emails + infrastructure)`\n );\n\n if (costs.tracking) {\n lines.push(\n ` - ${costs.tracking.description}: ${formatCost(costs.tracking.monthly)}`\n );\n }\n if (costs.reputationMetrics) {\n lines.push(\n ` - ${costs.reputationMetrics.description}: ${formatCost(costs.reputationMetrics.monthly)}`\n );\n }\n if (costs.eventTracking) {\n lines.push(\n ` - ${costs.eventTracking.description}: ${formatCost(costs.eventTracking.monthly)}`\n );\n }\n if (costs.dynamoDBHistory) {\n lines.push(\n ` - ${costs.dynamoDBHistory.description}: ${formatCost(costs.dynamoDBHistory.monthly)}`\n );\n }\n if (costs.emailArchiving) {\n lines.push(\n ` - ${costs.emailArchiving.description}: ${formatCost(costs.emailArchiving.monthly)}`\n );\n }\n if (costs.dedicatedIp) {\n lines.push(\n ` - ${costs.dedicatedIp.description}: ${formatCost(costs.dedicatedIp.monthly)}`\n );\n }\n\n return lines.join(\"\\n\");\n}\n","import type { ConfigPreset, WrapsEmailConfig } from \"../../types/index.js\";\nimport { calculateCosts, formatCost } from \"./costs.js\";\n\n/**\n * Preset configurations with recommended settings for different use cases\n */\n\n/**\n * Starter preset - minimal features for low-volume senders\n * Perfect for: Side projects, MVPs, development/staging\n * Volume: Up to 10k emails/month\n * Cost: ~$1-2/month (without archiving)\n */\nexport const STARTER_PRESET: WrapsEmailConfig = {\n tracking: {\n enabled: true,\n opens: true,\n clicks: true,\n },\n tlsRequired: true,\n reputationMetrics: false,\n suppressionList: {\n enabled: true,\n reasons: [\"BOUNCE\", \"COMPLAINT\"],\n },\n eventTracking: {\n enabled: false,\n },\n // Email archiving disabled by default\n emailArchiving: {\n enabled: false,\n retention: \"30days\",\n },\n sendingEnabled: true,\n};\n\n/**\n * Production preset - recommended for most production applications\n * Perfect for: SaaS apps, B2B products, moderate volume\n * Volume: 10k-500k emails/month\n * Cost: ~$10-50/month (scales with volume, add ~$5-15/mo for archiving)\n */\nexport const PRODUCTION_PRESET: WrapsEmailConfig = {\n tracking: {\n enabled: true,\n opens: true,\n clicks: true,\n },\n tlsRequired: true,\n reputationMetrics: true,\n suppressionList: {\n enabled: true,\n reasons: [\"BOUNCE\", \"COMPLAINT\"],\n },\n eventTracking: {\n enabled: true,\n eventBridge: true,\n events: [\n \"SEND\",\n \"DELIVERY\",\n \"OPEN\",\n \"CLICK\",\n \"BOUNCE\",\n \"COMPLAINT\",\n \"REJECT\",\n \"RENDERING_FAILURE\",\n ],\n dynamoDBHistory: true,\n archiveRetention: \"90days\",\n },\n // Email archiving with 90-day retention\n emailArchiving: {\n enabled: false, // User can opt-in\n retention: \"90days\",\n },\n sendingEnabled: true,\n};\n\n/**\n * Enterprise preset - full features for high-volume senders\n * Perfect for: Large platforms, high-volume transactional email\n * Volume: 500k+ emails/month\n * Cost: ~$100-200/month (includes $24.95 dedicated IP, add ~$50+/mo for archiving)\n */\nexport const ENTERPRISE_PRESET: WrapsEmailConfig = {\n tracking: {\n enabled: true,\n opens: true,\n clicks: true,\n },\n tlsRequired: true,\n reputationMetrics: true,\n suppressionList: {\n enabled: true,\n reasons: [\"BOUNCE\", \"COMPLAINT\"],\n },\n eventTracking: {\n enabled: true,\n eventBridge: true,\n events: [\n \"SEND\",\n \"DELIVERY\",\n \"OPEN\",\n \"CLICK\",\n \"BOUNCE\",\n \"COMPLAINT\",\n \"REJECT\",\n \"RENDERING_FAILURE\",\n \"DELIVERY_DELAY\",\n \"SUBSCRIPTION\",\n ],\n dynamoDBHistory: true,\n archiveRetention: \"1year\",\n },\n // Email archiving with 1-year retention\n emailArchiving: {\n enabled: false, // User can opt-in\n retention: \"1year\",\n },\n dedicatedIp: true,\n sendingEnabled: true,\n};\n\n/**\n * Get preset configuration by name\n */\nexport function getPreset(preset: ConfigPreset): WrapsEmailConfig | null {\n switch (preset) {\n case \"starter\":\n return STARTER_PRESET;\n case \"production\":\n return PRODUCTION_PRESET;\n case \"enterprise\":\n return ENTERPRISE_PRESET;\n case \"custom\":\n return null; // User will configure manually\n }\n}\n\n/**\n * Preset metadata for display\n */\nexport type PresetInfo = {\n name: string;\n description: string;\n recommended: string;\n volume: string;\n estimatedCost: string;\n features: string[];\n};\n\n/**\n * Get preset information for display\n */\nexport function getPresetInfo(preset: ConfigPreset): PresetInfo {\n const config = getPreset(preset);\n\n if (preset === \"custom\" || !config) {\n return {\n name: \"Custom\",\n description: \"Configure each feature individually\",\n recommended: \"Advanced users who need specific configuration\",\n volume: \"Any volume\",\n estimatedCost: \"Varies\",\n features: [\"Full control over all features\"],\n };\n }\n\n const costs = calculateCosts(\n config,\n preset === \"starter\"\n ? 10_000\n : preset === \"production\"\n ? 100_000\n : 1_000_000\n );\n\n const baseInfo = {\n starter: {\n name: \"Starter\",\n description: \"Minimal features for low-volume senders\",\n recommended: \"Side projects, MVPs, development/staging\",\n volume: \"Up to 10k emails/month\",\n features: [\n \"Open & click tracking\",\n \"TLS encryption required\",\n \"Automatic bounce/complaint suppression\",\n \"Optional: Email archiving (full content storage)\",\n ],\n },\n production: {\n name: \"Production\",\n description: \"Recommended for most production applications\",\n recommended: \"SaaS apps, B2B products, moderate volume (RECOMMENDED)\",\n volume: \"10k-500k emails/month\",\n features: [\n \"Everything in Starter\",\n \"Reputation tracking\",\n \"Real-time event tracking (EventBridge)\",\n \"90-day email history storage\",\n \"Optional: Email archiving with rendered viewer\",\n \"Complete event visibility\",\n ],\n },\n enterprise: {\n name: \"Enterprise\",\n description: \"Full features for high-volume senders\",\n recommended: \"Large platforms, high-volume transactional email\",\n volume: \"500k+ emails/month\",\n features: [\n \"Everything in Production\",\n \"Dedicated IP address\",\n \"1-year email history\",\n \"Optional: 1-year+ email archiving\",\n \"All event types tracked\",\n \"Priority support eligibility\",\n ],\n },\n }[preset];\n\n return {\n ...baseInfo,\n estimatedCost: formatCost(costs.total.monthly),\n } as PresetInfo;\n}\n\n/**\n * Get all preset options for CLI prompts\n */\nexport function getAllPresetInfo(): PresetInfo[] {\n return [\n getPresetInfo(\"starter\"),\n getPresetInfo(\"production\"),\n getPresetInfo(\"enterprise\"),\n getPresetInfo(\"custom\"),\n ];\n}\n\n/**\n * Compare two configurations to determine upgrade path\n */\nexport function getUpgradePath(\n current: WrapsEmailConfig,\n target: WrapsEmailConfig\n): string[] {\n const changes: string[] = [];\n\n // Check tracking changes\n if (!current.tracking?.enabled && target.tracking?.enabled) {\n changes.push(\"Enable email tracking (opens & clicks)\");\n }\n\n // Check reputation metrics\n if (!current.reputationMetrics && target.reputationMetrics) {\n changes.push(\"Enable reputation metrics\");\n }\n\n // Check event tracking\n if (!current.eventTracking?.enabled && target.eventTracking?.enabled) {\n changes.push(\"Enable real-time event tracking\");\n }\n\n // Check DynamoDB history\n if (\n !current.eventTracking?.dynamoDBHistory &&\n target.eventTracking?.dynamoDBHistory\n ) {\n changes.push(\"Enable email history storage\");\n }\n\n // Check retention upgrade\n if (\n current.eventTracking?.archiveRetention !==\n target.eventTracking?.archiveRetention &&\n target.eventTracking?.archiveRetention\n ) {\n changes.push(\n `Upgrade retention: ${current.eventTracking?.archiveRetention || \"none\"} → ${target.eventTracking.archiveRetention}`\n );\n }\n\n // Check dedicated IP\n if (!current.dedicatedIp && target.dedicatedIp) {\n changes.push(\"Add dedicated IP address\");\n }\n\n return changes;\n}\n\n/**\n * Validate configuration for common issues\n */\nexport function validateConfig(config: WrapsEmailConfig): string[] {\n const warnings: string[] = [];\n\n // Warn about dedicated IP without high volume\n if (config.dedicatedIp) {\n warnings.push(\n \"⚠️ Dedicated IPs require 100k+ emails/day for proper warmup. Consider starting with shared IPs.\"\n );\n }\n\n // Warn about event tracking without storage\n if (config.eventTracking?.enabled && !config.eventTracking?.dynamoDBHistory) {\n warnings.push(\n \"💡 Event tracking is enabled but history storage is disabled. Events will only be available in real-time.\"\n );\n }\n\n // Warn about long retention without need\n if (config.eventTracking?.archiveRetention === \"indefinite\") {\n warnings.push(\n \"⚠️ Indefinite retention can become expensive. Consider 90-day or 1-year retention.\"\n );\n }\n\n return warnings;\n}\n","import * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport type { ArchiveRetention } from \"../../types/index.js\";\n\n/**\n * Hosting provider type\n */\nexport type Provider = \"vercel\" | \"aws\" | \"railway\" | \"other\";\n\n/**\n * Prompt for hosting provider\n */\nexport async function promptProvider(): Promise<Provider> {\n const provider = await clack.select({\n message: \"Where is your app hosted?\",\n options: [\n {\n value: \"aws\",\n label: \"AWS (Lambda/ECS/EC2)\",\n hint: \"Uses IAM roles automatically\",\n },\n {\n value: \"vercel\",\n label: \"Vercel\",\n hint: \"Uses OIDC (no AWS credentials needed)\",\n },\n {\n value: \"railway\",\n label: \"Railway\",\n hint: \"Requires AWS credentials\",\n },\n {\n value: \"other\",\n label: \"Other\",\n hint: \"Will use AWS access keys\",\n },\n ],\n });\n\n if (clack.isCancel(provider)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return provider as Provider;\n}\n\n/**\n * Prompt for AWS region\n */\nexport async function promptRegion(defaultRegion: string): Promise<string> {\n const region = await clack.select({\n message: \"Select AWS region:\",\n options: [\n { value: \"us-east-1\", label: \"US East (N. Virginia)\", hint: \"us-east-1\" },\n { value: \"us-east-2\", label: \"US East (Ohio)\", hint: \"us-east-2\" },\n {\n value: \"us-west-1\",\n label: \"US West (N. California)\",\n hint: \"us-west-1\",\n },\n { value: \"us-west-2\", label: \"US West (Oregon)\", hint: \"us-west-2\" },\n { value: \"af-south-1\", label: \"Africa (Cape Town)\", hint: \"af-south-1\" },\n {\n value: \"ap-east-1\",\n label: \"Asia Pacific (Hong Kong)\",\n hint: \"ap-east-1\",\n },\n {\n value: \"ap-south-1\",\n label: \"Asia Pacific (Mumbai)\",\n hint: \"ap-south-1\",\n },\n {\n value: \"ap-northeast-1\",\n label: \"Asia Pacific (Tokyo)\",\n hint: \"ap-northeast-1\",\n },\n {\n value: \"ap-northeast-2\",\n label: \"Asia Pacific (Seoul)\",\n hint: \"ap-northeast-2\",\n },\n {\n value: \"ap-northeast-3\",\n label: \"Asia Pacific (Osaka)\",\n hint: \"ap-northeast-3\",\n },\n {\n value: \"ap-southeast-1\",\n label: \"Asia Pacific (Singapore)\",\n hint: \"ap-southeast-1\",\n },\n {\n value: \"ap-southeast-2\",\n label: \"Asia Pacific (Sydney)\",\n hint: \"ap-southeast-2\",\n },\n {\n value: \"ap-southeast-3\",\n label: \"Asia Pacific (Jakarta)\",\n hint: \"ap-southeast-3\",\n },\n {\n value: \"ca-central-1\",\n label: \"Canada (Central)\",\n hint: \"ca-central-1\",\n },\n {\n value: \"eu-central-1\",\n label: \"Europe (Frankfurt)\",\n hint: \"eu-central-1\",\n },\n { value: \"eu-west-1\", label: \"Europe (Ireland)\", hint: \"eu-west-1\" },\n { value: \"eu-west-2\", label: \"Europe (London)\", hint: \"eu-west-2\" },\n { value: \"eu-west-3\", label: \"Europe (Paris)\", hint: \"eu-west-3\" },\n { value: \"eu-south-1\", label: \"Europe (Milan)\", hint: \"eu-south-1\" },\n { value: \"eu-north-1\", label: \"Europe (Stockholm)\", hint: \"eu-north-1\" },\n {\n value: \"me-south-1\",\n label: \"Middle East (Bahrain)\",\n hint: \"me-south-1\",\n },\n {\n value: \"sa-east-1\",\n label: \"South America (São Paulo)\",\n hint: \"sa-east-1\",\n },\n ],\n initialValue: defaultRegion || \"us-east-1\",\n });\n\n if (clack.isCancel(region)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return region as string;\n}\n\n/**\n * Prompt for domain to verify (optional)\n */\nexport async function promptDomain(): Promise<string> {\n const domain = await clack.text({\n message: \"Domain to verify (optional):\",\n placeholder: \"myapp.com\",\n validate: (value) => {\n if (!value) {\n return; // Optional\n }\n if (!value.includes(\".\")) {\n return \"Please enter a valid domain (e.g., myapp.com)\";\n }\n },\n });\n\n if (clack.isCancel(domain)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return domain || \"\";\n}\n\n/**\n * Vercel configuration\n */\nexport type VercelConfig = {\n teamSlug: string;\n projectName: string;\n};\n\n/**\n * Prompt for Vercel configuration\n */\nexport async function promptVercelConfig(): Promise<VercelConfig> {\n const config = await clack.group(\n {\n teamSlug: () =>\n clack.text({\n message: \"Vercel team slug:\",\n placeholder: \"my-team\",\n validate: (value) => {\n if (!value) {\n return \"Team slug is required for Vercel integration\";\n }\n },\n }),\n projectName: () =>\n clack.text({\n message: \"Vercel project name:\",\n placeholder: \"my-project\",\n validate: (value) => {\n if (!value) {\n return \"Project name is required\";\n }\n },\n }),\n },\n {\n onCancel: () => {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n },\n }\n );\n\n return config as VercelConfig;\n}\n\n/**\n * Prompt for integration level\n */\nexport async function promptIntegrationLevel(): Promise<\n \"dashboard-only\" | \"enhanced\"\n> {\n const level = await clack.select({\n message: \"Integration level:\",\n options: [\n {\n value: \"enhanced\",\n label: \"Enhanced (full email tracking)\",\n hint: \"Creates SES config, DynamoDB, Lambda functions\",\n },\n {\n value: \"dashboard-only\",\n label: \"Dashboard-only (read-only)\",\n hint: \"Only creates IAM role for dashboard access\",\n },\n ],\n });\n\n if (clack.isCancel(level)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return level as \"dashboard-only\" | \"enhanced\";\n}\n\n/**\n * Confirm deployment\n */\nexport async function confirmDeploy(): Promise<boolean> {\n const confirmed = await clack.confirm({\n message: \"Deploy infrastructure to your AWS account?\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirmed)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return confirmed;\n}\n\n/**\n * Feature definition for multi-select\n */\nexport type FeatureOption = {\n value: string;\n label: string;\n hint: string;\n};\n\n/**\n * Get available features\n */\nexport function getAvailableFeatures(): FeatureOption[] {\n return [\n {\n value: \"configSet\",\n label: \"Configuration Set\",\n hint: \"Track opens, clicks, bounces, and complaints\",\n },\n {\n value: \"bounceHandling\",\n label: \"Bounce Handling\",\n hint: \"Automatically process bounce notifications\",\n },\n {\n value: \"complaintHandling\",\n label: \"Complaint Handling\",\n hint: \"Automatically process spam complaints\",\n },\n {\n value: \"emailHistory\",\n label: \"Email History\",\n hint: \"Store sent emails in DynamoDB (90-day retention)\",\n },\n {\n value: \"eventProcessor\",\n label: \"Event Processor\",\n hint: \"Advanced analytics and webhook forwarding\",\n },\n {\n value: \"dashboardAccess\",\n label: \"Dashboard Access\",\n hint: \"Read-only IAM role for web dashboard\",\n },\n ];\n}\n\n/**\n * Prompt for feature selection (multi-select)\n */\nexport async function promptFeatureSelection(\n preselected?: string[]\n): Promise<string[]> {\n const features = getAvailableFeatures();\n\n const selected = await clack.multiselect({\n message: \"Select features to deploy:\",\n options: features,\n initialValues: preselected || [\n \"configSet\",\n \"bounceHandling\",\n \"complaintHandling\",\n \"dashboardAccess\",\n ],\n required: true,\n });\n\n if (clack.isCancel(selected)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return selected as string[];\n}\n\n/**\n * Conflict resolution action\n */\nexport type ConflictAction = \"deploy-alongside\" | \"replace\" | \"skip\";\n\n/**\n * Prompt for conflict resolution\n */\nexport async function promptConflictResolution(\n resourceType: string,\n existingResourceName: string\n): Promise<ConflictAction> {\n const action = await clack.select({\n message: `Found existing ${resourceType}: ${pc.cyan(existingResourceName)}. How should we handle this?`,\n options: [\n {\n value: \"deploy-alongside\",\n label: \"Deploy alongside (no changes)\",\n hint: \"Create our resources without modifying yours\",\n },\n {\n value: \"replace\",\n label: \"Replace with Wraps version\",\n hint: \"Save original for restore, use ours\",\n },\n {\n value: \"skip\",\n label: \"Skip this feature\",\n hint: \"Keep your setup, skip Wraps deployment\",\n },\n ],\n });\n\n if (clack.isCancel(action)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return action as ConflictAction;\n}\n\n/**\n * Prompt to select identities to track\n */\nexport async function promptSelectIdentities(\n identities: Array<{ name: string; verified: boolean }>\n): Promise<string[]> {\n const selected = await clack.multiselect({\n message: \"Select identities to connect with Wraps:\",\n options: identities.map((id) => ({\n value: id.name,\n label: id.name,\n hint: id.verified ? \"Verified\" : \"Pending verification\",\n })),\n required: false,\n });\n\n if (clack.isCancel(selected)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return selected as string[];\n}\n\n/**\n * Confirm connection deployment\n */\nexport async function confirmConnect(): Promise<boolean> {\n const confirmed = await clack.confirm({\n message: \"Connect to existing AWS infrastructure?\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirmed)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return confirmed;\n}\n\n/**\n * Prompt for configuration preset\n */\nexport async function promptConfigPreset(): Promise<\n \"starter\" | \"production\" | \"enterprise\" | \"custom\"\n> {\n const { getAllPresetInfo } = await import(\"../email/presets.js\");\n const presets = getAllPresetInfo();\n\n const preset = await clack.select({\n message: \"Choose a configuration preset:\",\n options: presets.map((p: any) => ({\n value: p.name.toLowerCase() as\n | \"starter\"\n | \"production\"\n | \"enterprise\"\n | \"custom\",\n label: `${p.name} - ${p.description}`,\n hint: `${p.volume} | Est. ${p.estimatedCost}/mo`,\n })),\n });\n\n if (clack.isCancel(preset)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return preset as \"starter\" | \"production\" | \"enterprise\" | \"custom\";\n}\n\n/**\n * Prompt for estimated monthly email volume\n */\nexport async function promptEstimatedVolume(): Promise<number> {\n const volume = await clack.select({\n message: \"Estimated monthly email volume:\",\n options: [\n { value: 1000, label: \"< 1k emails/month\", hint: \"Hobby/Development\" },\n { value: 10_000, label: \"1k-10k emails/month\", hint: \"Side Project\" },\n {\n value: 50_000,\n label: \"10k-100k emails/month\",\n hint: \"Growing Startup\",\n },\n {\n value: 250_000,\n label: \"100k-500k emails/month\",\n hint: \"Production SaaS\",\n },\n { value: 1_000_000, label: \"500k+ emails/month\", hint: \"High Volume\" },\n ],\n });\n\n if (clack.isCancel(volume)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return volume as number;\n}\n\n/**\n * Prompt for custom configuration\n */\n/**\n * Prompt for email archiving configuration (for presets)\n */\nexport async function promptEmailArchiving(): Promise<{\n enabled: boolean;\n retention: ArchiveRetention;\n}> {\n const enabled = await clack.confirm({\n message:\n \"Enable email archiving? (Store full email content with HTML for viewing in dashboard)\",\n initialValue: false,\n });\n\n if (clack.isCancel(enabled)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n if (!enabled) {\n return { enabled: false, retention: \"90days\" };\n }\n\n const retention = await clack.select({\n message: \"Email archive retention period:\",\n options: [\n { value: \"7days\", label: \"7 days\", hint: \"~$1-2/mo for 10k emails\" },\n { value: \"30days\", label: \"30 days\", hint: \"~$2-4/mo for 10k emails\" },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"~$5-10/mo for 10k emails\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"~$15-25/mo for 10k emails\",\n },\n { value: \"1year\", label: \"1 year\", hint: \"~$25-40/mo for 10k emails\" },\n {\n value: \"18months\",\n label: \"18 months\",\n hint: \"~$35-60/mo for 10k emails\",\n },\n ],\n initialValue: \"90days\",\n });\n\n if (clack.isCancel(retention)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n clack.log.info(\n pc.dim(\n \"Archiving stores full RFC 822 emails with HTML, attachments, and headers\"\n )\n );\n clack.log.info(\n pc.dim(\"Cost: $2/GB ingestion + $0.19/GB/month storage (~50KB per email)\")\n );\n\n return {\n enabled: true,\n retention: retention as ArchiveRetention,\n };\n}\n\nexport async function promptCustomConfig(existingConfig?: any): Promise<any> {\n clack.log.info(\"Custom configuration builder\");\n clack.log.info(\"Configure each feature individually\");\n\n // Reputation tracking (first, as it's recommended)\n const reputationMetrics = await clack.confirm({\n message: \"Enable reputation tracking (recommended)?\",\n initialValue: existingConfig?.reputationMetrics ?? true,\n });\n\n if (clack.isCancel(reputationMetrics)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n // Tracking\n const trackingEnabled = await clack.confirm({\n message: \"Enable open & click tracking?\",\n initialValue: existingConfig?.tracking?.enabled ?? true,\n });\n\n if (clack.isCancel(trackingEnabled)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n // Event tracking (combined - EventBridge + DynamoDB)\n const eventTrackingEnabled = await clack.confirm({\n message: \"Store email events in DynamoDB?\",\n initialValue: existingConfig?.eventTracking?.enabled ?? true,\n });\n\n if (clack.isCancel(eventTrackingEnabled)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n let archiveRetention: string | symbol = \"90days\";\n\n if (eventTrackingEnabled) {\n archiveRetention = await clack.select({\n message: \"Event history retention period:\",\n options: [\n { value: \"7days\", label: \"7 days\", hint: \"Minimal storage cost\" },\n { value: \"30days\", label: \"30 days\", hint: \"Development/testing\" },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"Standard retention\",\n },\n { value: \"1year\", label: \"1 year\", hint: \"Compliance requirements\" },\n {\n value: \"indefinite\",\n label: \"Indefinite\",\n hint: \"Higher storage cost\",\n },\n ],\n initialValue: existingConfig?.eventTracking?.archiveRetention || \"90days\",\n });\n\n if (clack.isCancel(archiveRetention)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n }\n\n // Security\n const tlsRequired = await clack.confirm({\n message: \"Require TLS encryption for all emails?\",\n initialValue: existingConfig?.tlsRequired ?? true,\n });\n\n if (clack.isCancel(tlsRequired)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n // Custom MAIL FROM domain (for DMARC alignment)\n const customMailFrom = await clack.confirm({\n message: \"Configure custom MAIL FROM domain? (improves DMARC alignment)\",\n initialValue: existingConfig?.mailFromDomain !== undefined,\n });\n\n if (clack.isCancel(customMailFrom)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n let mailFromSubdomain: string | symbol = \"mail\";\n\n if (customMailFrom) {\n mailFromSubdomain = await clack.text({\n message: \"MAIL FROM subdomain:\",\n placeholder: \"mail\",\n initialValue: existingConfig?.mailFromDomain?.split(\".\")[0] || \"mail\",\n validate: (value) => {\n if (!value || value.trim() === \"\") {\n return \"Subdomain is required\";\n }\n if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/i.test(value)) {\n return \"Invalid subdomain format\";\n }\n return;\n },\n });\n\n if (clack.isCancel(mailFromSubdomain)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n clack.log.info(\n pc.dim(`MAIL FROM will be set to ${mailFromSubdomain}.yourdomain.com`)\n );\n }\n\n // Dedicated IP\n const dedicatedIp = await clack.confirm({\n message: \"Request dedicated IP address? (requires 100k+ emails/day)\",\n initialValue: existingConfig?.dedicatedIp ?? false,\n });\n\n if (clack.isCancel(dedicatedIp)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n // Email Archiving\n const emailArchivingEnabled = await clack.confirm({\n message:\n \"Enable email archiving? (Store full email content with HTML for viewing)\",\n initialValue: existingConfig?.emailArchiving?.enabled ?? false,\n });\n\n if (clack.isCancel(emailArchivingEnabled)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n let emailArchiveRetention: string | symbol = \"90days\";\n\n if (emailArchivingEnabled) {\n emailArchiveRetention = await clack.select({\n message: \"Email archive retention period:\",\n options: [\n { value: \"7days\", label: \"7 days\", hint: \"~$1-2/mo for 10k emails\" },\n { value: \"30days\", label: \"30 days\", hint: \"~$2-4/mo for 10k emails\" },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"~$5-10/mo for 10k emails\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"~$15-25/mo for 10k emails\",\n },\n { value: \"1year\", label: \"1 year\", hint: \"~$25-40/mo for 10k emails\" },\n {\n value: \"18months\",\n label: \"18 months\",\n hint: \"~$35-60/mo for 10k emails\",\n },\n ],\n initialValue: existingConfig?.emailArchiving?.retention || \"90days\",\n });\n\n if (clack.isCancel(emailArchiveRetention)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n clack.log.info(\n pc.dim(\n \"Note: Archiving stores full RFC 822 emails with HTML, attachments, and headers\"\n )\n );\n clack.log.info(\n pc.dim(\"Cost: $2/GB ingestion + $0.19/GB/month storage (~50KB per email)\")\n );\n }\n\n return {\n tracking: trackingEnabled\n ? {\n enabled: true,\n opens: true,\n clicks: true,\n }\n : { enabled: false },\n tlsRequired,\n reputationMetrics,\n mailFromSubdomain: customMailFrom\n ? typeof mailFromSubdomain === \"string\"\n ? mailFromSubdomain\n : \"mail\"\n : undefined,\n suppressionList: {\n enabled: true,\n reasons: [\"BOUNCE\", \"COMPLAINT\"],\n },\n eventTracking: eventTrackingEnabled\n ? {\n enabled: true,\n eventBridge: true,\n events: [\n \"SEND\",\n \"DELIVERY\",\n \"OPEN\",\n \"CLICK\",\n \"BOUNCE\",\n \"COMPLAINT\",\n \"REJECT\",\n \"RENDERING_FAILURE\",\n ],\n dynamoDBHistory: true,\n archiveRetention:\n typeof archiveRetention === \"string\" ? archiveRetention : \"90days\",\n }\n : { enabled: false },\n emailArchiving: emailArchivingEnabled\n ? {\n enabled: true,\n retention:\n typeof emailArchiveRetention === \"string\"\n ? emailArchiveRetention\n : \"90days\",\n }\n : { enabled: false, retention: \"90days\" },\n dedicatedIp,\n sendingEnabled: true,\n };\n}\n\n/**\n * DNS record category labels for display\n */\nconst DNS_CATEGORY_LABELS: Record<string, string> = {\n dkim: \"DKIM (Email Authentication)\",\n spf: \"SPF (Sender Policy Framework)\",\n dmarc: \"DMARC (Email Policy)\",\n tracking: \"Tracking Domain\",\n mailfrom_mx: \"MAIL FROM (MX Record)\",\n mailfrom_spf: \"MAIL FROM (SPF Record)\",\n};\n\n/**\n * Status symbols for DNS records\n */\nconst DNS_STATUS_SYMBOLS: Record<string, string> = {\n new: pc.green(\"+ NEW\"),\n update: pc.yellow(\"~ UPDATE\"),\n conflict: pc.red(\"! CONFLICT\"),\n no_change: pc.dim(\"✓ OK\"),\n};\n\n/**\n * Display a DNS record for review\n */\nfunction formatDNSRecord(record: {\n name: string;\n type: string;\n proposedValue: string;\n existingValue: string | null;\n status: string;\n category: string;\n conflictReason?: string;\n}): string {\n const lines: string[] = [];\n const statusSymbol =\n DNS_STATUS_SYMBOLS[record.status] || pc.dim(record.status);\n const categoryLabel =\n DNS_CATEGORY_LABELS[record.category] || record.category;\n\n lines.push(` ${statusSymbol} ${pc.bold(categoryLabel)}`);\n lines.push(` ${pc.dim(\"Name:\")} ${record.name}`);\n lines.push(` ${pc.dim(\"Type:\")} ${record.type}`);\n\n if (record.existingValue && record.status !== \"no_change\") {\n lines.push(` ${pc.dim(\"Current:\")} ${pc.red(record.existingValue)}`);\n lines.push(` ${pc.dim(\"New:\")} ${pc.green(record.proposedValue)}`);\n } else if (record.status === \"new\") {\n lines.push(` ${pc.dim(\"Value:\")} ${pc.green(record.proposedValue)}`);\n } else {\n lines.push(` ${pc.dim(\"Value:\")} ${record.proposedValue}`);\n }\n\n if (record.conflictReason) {\n lines.push(` ${pc.red(\"⚠ \" + record.conflictReason)}`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Prompt for DNS record confirmation with conflict detection\n * Shows all proposed records and lets user select which to create\n */\nexport async function promptDNSConfirmation(preview: {\n records: Array<{\n name: string;\n type: string;\n proposedValue: string;\n existingValue: string | null;\n status: string;\n category: string;\n conflictReason?: string;\n }>;\n hasConflicts: boolean;\n conflictCount: number;\n newCount: number;\n updateCount: number;\n noChangeCount: number;\n}): Promise<{\n shouldCreate: boolean;\n selectedCategories: Set<string>;\n}> {\n console.log();\n clack.log.info(pc.bold(\"DNS Record Review\"));\n console.log();\n\n // Show summary\n const summaryParts: string[] = [];\n if (preview.newCount > 0) {\n summaryParts.push(pc.green(`${preview.newCount} new`));\n }\n if (preview.updateCount > 0) {\n summaryParts.push(pc.yellow(`${preview.updateCount} updates`));\n }\n if (preview.conflictCount > 0) {\n summaryParts.push(pc.red(`${preview.conflictCount} conflicts`));\n }\n if (preview.noChangeCount > 0) {\n summaryParts.push(pc.dim(`${preview.noChangeCount} unchanged`));\n }\n console.log(` ${summaryParts.join(\" | \")}\\n`);\n\n // Display all records\n for (const record of preview.records) {\n console.log(formatDNSRecord(record));\n console.log();\n }\n\n // If there are conflicts, show a warning\n if (preview.hasConflicts) {\n clack.log.warn(\n pc.yellow(\n \"Some records have conflicts. Creating them will overwrite existing values.\"\n )\n );\n console.log();\n }\n\n // If everything is unchanged, skip the prompt\n if (\n preview.newCount === 0 &&\n preview.updateCount === 0 &&\n preview.conflictCount === 0\n ) {\n clack.log.success(\"All DNS records are already configured correctly.\");\n return { shouldCreate: false, selectedCategories: new Set() };\n }\n\n // Ask if user wants to create DNS records\n const shouldCreate = await clack.confirm({\n message: \"Create DNS records in Route53?\",\n initialValue: !preview.hasConflicts, // Default to no if there are conflicts\n });\n\n if (clack.isCancel(shouldCreate) || !shouldCreate) {\n return { shouldCreate: false, selectedCategories: new Set() };\n }\n\n // If there are conflicts or updates, let user select which records to create\n if (preview.hasConflicts || preview.updateCount > 0) {\n const recordsToSelect = preview.records.filter(\n (r) => r.status !== \"no_change\"\n );\n\n // Group by category to avoid duplicate entries (e.g., multiple DKIM records)\n const categories = new Map<string, { status: string; hasConflict: boolean }>();\n for (const record of recordsToSelect) {\n const existing = categories.get(record.category);\n if (!existing || record.status === \"conflict\") {\n categories.set(record.category, {\n status: record.status,\n hasConflict: record.status === \"conflict\",\n });\n }\n }\n\n const options = Array.from(categories.entries()).map(\n ([category, info]) => {\n const label = DNS_CATEGORY_LABELS[category] || category;\n let hint =\n info.status === \"new\"\n ? \"New\"\n : info.status === \"update\"\n ? \"Will merge with existing\"\n : \"Will replace existing\";\n if (info.hasConflict) {\n hint = pc.red(hint + \" ⚠\");\n }\n return {\n value: category,\n label,\n hint,\n };\n }\n );\n\n // Pre-select non-conflict records\n const initialValues = Array.from(categories.entries())\n .filter(([_, info]) => !info.hasConflict)\n .map(([category]) => category);\n\n const selected = await clack.multiselect({\n message: \"Select which records to create:\",\n options,\n initialValues,\n required: false,\n });\n\n if (clack.isCancel(selected)) {\n return { shouldCreate: false, selectedCategories: new Set() };\n }\n\n return {\n shouldCreate: true,\n selectedCategories: new Set(selected as string[]),\n };\n }\n\n // No conflicts - select all new/update records\n const allCategories = new Set(\n preview.records\n .filter((r) => r.status !== \"no_change\")\n .map((r) => r.category)\n );\n\n return { shouldCreate: true, selectedCategories: allCategories };\n}\n\n/**\n * Ask user if they want to manage DNS records via Route53\n */\nexport async function promptDNSManagement(domain: string): Promise<boolean> {\n const manage = await clack.confirm({\n message: `Manage DNS records for ${pc.cyan(domain)} via Route53?`,\n initialValue: true,\n });\n\n if (clack.isCancel(manage)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return manage;\n}\n","import { AssumeRoleCommand, STSClient } from \"@aws-sdk/client-sts\";\n\n/**\n * AWS credential identity type\n */\nexport type AwsCredentialIdentity = {\n accessKeyId: string;\n secretAccessKey: string;\n sessionToken?: string;\n expiration?: Date;\n};\n\n/**\n * Assume IAM role and return temporary credentials\n */\nexport async function assumeRole(\n roleArn: string,\n region: string,\n sessionName = \"wraps-console\"\n): Promise<AwsCredentialIdentity> {\n const sts = new STSClient({ region });\n\n const response = await sts.send(\n new AssumeRoleCommand({\n RoleArn: roleArn,\n RoleSessionName: sessionName,\n DurationSeconds: 3600, // 1 hour\n })\n );\n\n if (!response.Credentials) {\n throw new Error(\"Failed to assume role: No credentials returned\");\n }\n\n return {\n accessKeyId: response.Credentials.AccessKeyId!,\n secretAccessKey: response.Credentials.SecretAccessKey!,\n sessionToken: response.Credentials.SessionToken!,\n expiration: response.Credentials.Expiration,\n };\n}\n","import {\n GetArchiveMessageCommand,\n type GetArchiveMessageCommandOutput,\n GetArchiveSearchResultsCommand,\n MailManagerClient,\n StartArchiveSearchCommand,\n} from \"@aws-sdk/client-mailmanager\";\nimport DOMPurify from \"isomorphic-dompurify\";\nimport { type ParsedMail, simpleParser } from \"mailparser\";\n\n/**\n * Parsed email from archive\n */\nexport type ParsedEmail = {\n messageId: string;\n from: string;\n to: string;\n subject: string;\n html?: string;\n text?: string;\n attachments: Array<{\n filename?: string;\n contentType: string;\n size: number;\n }>;\n headers: Record<string, string | string[] | undefined>;\n timestamp: Date;\n metadata?: {\n senderIp?: string;\n tlsProtocol?: string;\n tlsCipherSuite?: string;\n senderHostname?: string;\n };\n};\n\n/**\n * Extract archive ID from ARN\n * ARN format: arn:aws:ses:region:account-id:mailmanager-archive/archive-id\n * Returns just the archive-id part\n */\nfunction extractArchiveId(archiveArnOrId: string): string {\n if (archiveArnOrId.startsWith(\"arn:\")) {\n // Extract ID from ARN\n const parts = archiveArnOrId.split(\"/\");\n return parts.at(-1) as string;\n }\n // Already just an ID\n return archiveArnOrId;\n}\n\n/**\n * Search criteria for finding archived email\n */\nexport type ArchiveSearchCriteria = {\n from?: string;\n to?: string;\n subject?: string;\n timestamp?: Date;\n};\n\n/**\n * Get an archived email using search criteria\n *\n * This function performs a two-step process:\n * 1. Search the archive using FROM/TO/SUBJECT to find the ArchivedMessageId\n * 2. Retrieve the actual email content using the ArchivedMessageId\n *\n * Note: MailManager Archive doesn't support searching by SES Message-ID directly.\n * We search using FROM, TO, and SUBJECT which we get from DynamoDB events.\n *\n * @param archiveArnOrId Archive ARN or ID (will extract ID if ARN provided)\n * @param searchCriteria Email search criteria (from, to, subject, timestamp)\n * @param region AWS region\n * @returns Parsed email with full content\n */\nexport async function getArchivedEmail(\n archiveArnOrId: string,\n searchCriteria: ArchiveSearchCriteria,\n region: string\n): Promise<ParsedEmail> {\n const client = new MailManagerClient({ region });\n\n // Extract archive ID from ARN if needed\n const archiveId = extractArchiveId(archiveArnOrId);\n\n // Step 1: Search for the message to get the ArchivedMessageId\n // MailManager doesn't support MESSAGE_ID search, so we use FROM/TO/SUBJECT\n // Use timestamp to narrow the search window (±1 day)\n const searchTime = searchCriteria.timestamp || new Date();\n const dayBefore = new Date(searchTime.getTime() - 24 * 60 * 60 * 1000);\n const dayAfter = new Date(searchTime.getTime() + 24 * 60 * 60 * 1000);\n\n // Build search filters\n const filters: any[] = [];\n\n if (searchCriteria.from) {\n filters.push({\n StringExpression: {\n Evaluate: {\n Attribute: \"FROM\",\n },\n Operator: \"CONTAINS\",\n Values: [searchCriteria.from],\n },\n });\n }\n\n if (searchCriteria.to) {\n filters.push({\n StringExpression: {\n Evaluate: {\n Attribute: \"TO\",\n },\n Operator: \"CONTAINS\",\n Values: [searchCriteria.to],\n },\n });\n }\n\n if (searchCriteria.subject) {\n filters.push({\n StringExpression: {\n Evaluate: {\n Attribute: \"SUBJECT\",\n },\n Operator: \"CONTAINS\",\n Values: [searchCriteria.subject],\n },\n });\n }\n\n // If no filters provided, throw error\n if (filters.length === 0) {\n throw new Error(\n \"At least one search criterion (from, to, or subject) is required\"\n );\n }\n\n const searchCommand = new StartArchiveSearchCommand({\n ArchiveId: archiveId,\n FromTimestamp: dayBefore,\n ToTimestamp: dayAfter,\n Filters: {\n Include: filters,\n },\n MaxResults: 10, // Get a few results in case there are multiple matches\n });\n\n const searchResponse = await client.send(searchCommand);\n const searchId = searchResponse.SearchId;\n\n if (!searchId) {\n throw new Error(\"Failed to start archive search\");\n }\n\n // Step 2: Poll for search results (searches are async)\n let archivedMessageId: string | undefined;\n let attempts = 0;\n const maxAttempts = 20; // Increased max attempts\n const pollInterval = 1000; // 1 second between polls\n\n // Wait a bit before first poll to let search start\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n while (attempts < maxAttempts) {\n try {\n const resultsCommand = new GetArchiveSearchResultsCommand({\n SearchId: searchId,\n });\n\n const resultsResponse = await client.send(resultsCommand);\n\n if (resultsResponse.Rows && resultsResponse.Rows.length > 0) {\n // Found the message!\n archivedMessageId = resultsResponse.Rows[0].ArchivedMessageId;\n break;\n }\n\n // No results yet, but search completed - email not found\n if (resultsResponse.Rows && resultsResponse.Rows.length === 0) {\n // Search completed but no results\n break;\n }\n } catch (error: unknown) {\n // If search is still in progress, continue polling\n if (\n error instanceof Error &&\n error.name === \"ConflictException\" &&\n error.message.includes(\"still in progress\")\n ) {\n console.log(`Search still in progress, attempt ${attempts + 1}...`);\n } else {\n // Other errors should be thrown\n throw error;\n }\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n attempts++;\n }\n\n if (!archivedMessageId) {\n throw new Error(\n \"Email not found in archive with the provided search criteria. It may have been sent before archiving was enabled.\"\n );\n }\n\n // Step 3: Get the actual archived message using the ArchivedMessageId\n const command = new GetArchiveMessageCommand({\n ArchivedMessageId: archivedMessageId,\n });\n\n const response: GetArchiveMessageCommandOutput = await client.send(command);\n\n if (!response.MessageDownloadLink) {\n throw new Error(\"No download link available for archived message\");\n }\n\n // Download raw email from presigned S3 URL\n const emailResponse = await fetch(response.MessageDownloadLink);\n if (!emailResponse.ok) {\n throw new Error(`Failed to download email: ${emailResponse.statusText}`);\n }\n\n const emailRaw = await emailResponse.text();\n\n // Parse RFC 822/MIME message\n const parsed: ParsedMail = await simpleParser(emailRaw);\n\n // Extract attachment metadata (don't include full content to save memory)\n const attachments =\n parsed.attachments?.map((att) => ({\n filename: att.filename,\n contentType: att.contentType,\n size: att.size,\n })) || [];\n\n // Convert headers Map to plain object\n const headers: Record<string, string | string[] | undefined> = {};\n if (parsed.headers) {\n for (const [key, value] of parsed.headers) {\n // Convert header values to string/string[]\n if (value instanceof Date) {\n headers[key] = value.toISOString();\n } else if (typeof value === \"string\") {\n headers[key] = value;\n } else if (\n Array.isArray(value) &&\n value.every((v) => typeof v === \"string\")\n ) {\n headers[key] = value as string[];\n } else {\n // Convert complex header types (AddressObject, StructuredHeader, etc.) to string\n headers[key] = JSON.stringify(value);\n }\n }\n }\n\n // Extract from/to as text\n const getAddressText = (\n addr: ParsedMail[\"from\"] | ParsedMail[\"to\"]\n ): string => {\n if (!addr) {\n return \"\";\n }\n if (Array.isArray(addr)) {\n return addr.map((a) => a.text).join(\", \");\n }\n return addr.text || \"\";\n };\n\n return {\n messageId: parsed.messageId || headers[\"message-id\"]?.toString() || \"\",\n from: getAddressText(parsed.from),\n to: getAddressText(parsed.to),\n subject: parsed.subject || \"\",\n html: parsed.html || undefined,\n text: parsed.text || undefined,\n attachments,\n headers,\n timestamp: parsed.date || new Date(),\n // Note: MessageMetadata is not available in GetArchiveMessageCommandOutput\n // These fields would need to be retrieved separately if needed\n metadata: {},\n };\n}\n\n/**\n * Search archived emails\n *\n * TODO: Update this to use the correct Mail Manager Archive Search API:\n * - StartArchiveSearchCommand to initiate search\n * - GetArchiveSearchResultsCommand to retrieve results\n * - Implement polling logic for async search completion\n *\n * @param archiveId Archive ARN or ID\n * @param params Search parameters\n * @param region AWS region\n * @returns Search results\n */\nexport async function searchArchivedEmails(\n archiveId: string,\n params: {\n from?: string;\n to?: string;\n subject?: string;\n startDate?: Date;\n endDate?: Date;\n maxResults?: number;\n },\n region: string\n): Promise<never> {\n // TODO: Implement proper search using StartArchiveSearchCommand\n // and GetArchiveSearchResultsCommand\n // Suppress unused variable warnings\n void archiveId;\n void params;\n void region;\n\n throw new Error(\n \"Archive search is not yet implemented. This requires:\\n\" +\n \"1. Start search with StartArchiveSearchCommand\\n\" +\n \"2. Poll for completion\\n\" +\n \"3. Get results with GetArchiveSearchResultsCommand\"\n );\n}\n\n/**\n * Sanitize HTML for safe rendering using DOMPurify\n * Removes potentially dangerous elements and attributes\n *\n * Uses isomorphic-dompurify which provides secure HTML sanitization\n * that works in both Node.js and browser environments.\n *\n * @param html HTML content to sanitize\n * @returns Sanitized HTML safe for rendering\n */\nexport function sanitizeEmailHtml(html: string): string {\n // DOMPurify provides comprehensive XSS protection including:\n // - Script tag removal (including nested bypass attacks like <scr<script>ipt>)\n // - Event handler removal (onclick, onload, etc.)\n // - Protocol sanitization (javascript:, data:text/html, etc.)\n // - Object/embed/iframe removal\n // - Style-based XSS protection\n return DOMPurify.sanitize(html, {\n // Allow common safe HTML elements for email rendering\n ALLOWED_TAGS: [\n \"p\",\n \"div\",\n \"span\",\n \"a\",\n \"img\",\n \"br\",\n \"strong\",\n \"em\",\n \"b\",\n \"i\",\n \"u\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"ul\",\n \"ol\",\n \"li\",\n \"table\",\n \"thead\",\n \"tbody\",\n \"tr\",\n \"td\",\n \"th\",\n \"blockquote\",\n \"pre\",\n \"code\",\n ],\n ALLOWED_ATTR: [\"href\", \"src\", \"alt\", \"title\", \"class\", \"style\", \"target\"],\n // Keep safe URIs only (removes javascript:, data:text/html, etc.)\n ALLOW_DATA_ATTR: false,\n });\n}\n","import {\n type ArchiveSearchCriteria,\n getArchivedEmail,\n} from \"../../utils/archive.js\";\n\n/**\n * Archived email with full content\n */\nexport type ArchivedEmail = {\n messageId: string;\n from: string;\n to: string;\n subject: string;\n html?: string;\n text?: string;\n attachments: Array<{\n filename?: string;\n contentType: string;\n size: number;\n }>;\n headers: Record<string, string | string[] | undefined>;\n timestamp: Date;\n metadata?: {\n senderIp?: string;\n tlsProtocol?: string;\n tlsCipherSuite?: string;\n senderHostname?: string;\n };\n};\n\ntype FetchArchivedEmailOptions = {\n region: string;\n archiveArn: string;\n from?: string;\n to?: string;\n subject?: string;\n timestamp?: Date;\n};\n\n/**\n * Fetch archived email by message ID from AWS SES Mail Manager\n *\n * This function searches the archive using email metadata (from, to, subject)\n * to find the archived message, since MailManager doesn't support direct\n * search by SES Message-ID.\n *\n * @param messageId Email message ID (for logging/correlation only)\n * @param options Configuration options including search criteria\n * @returns Archived email with full content, or null if not found\n */\nexport async function fetchArchivedEmail(\n messageId: string,\n options: FetchArchivedEmailOptions\n): Promise<ArchivedEmail | null> {\n const { region, archiveArn, from, to, subject, timestamp } = options;\n\n try {\n console.log(\"Fetching archived email:\", {\n messageId,\n archiveArn,\n region,\n });\n\n // Build search criteria from email metadata\n const searchCriteria: ArchiveSearchCriteria = {\n from,\n to,\n subject,\n timestamp,\n };\n\n // Call the archive utility to get the email\n const email = await getArchivedEmail(archiveArn, searchCriteria, region);\n\n console.log(\"Archived email fetched successfully:\", {\n messageId: email.messageId,\n hasHtml: !!email.html,\n hasText: !!email.text,\n attachmentCount: email.attachments.length,\n });\n\n // Return the email data\n return email;\n } catch (error: unknown) {\n // If the email is not found, return null instead of throwing\n if (\n error instanceof Error &&\n (error.message.includes(\"not found\") ||\n error.message.includes(\"ResourceNotFoundException\"))\n ) {\n console.log(\"Archived email not found:\", messageId);\n return null;\n }\n\n // For other errors, log and rethrow\n console.error(\"Error fetching archived email:\", error);\n throw error;\n }\n}\n","import { DynamoDBClient, ScanCommand } from \"@aws-sdk/client-dynamodb\";\nimport { unmarshall } from \"@aws-sdk/util-dynamodb\";\n\nexport type DynamoDBMetrics = {\n opens: Array<{ timestamp: number; value: number }>;\n clicks: Array<{ timestamp: number; value: number }>;\n};\n\n/**\n * Fetch Open and Click metrics from DynamoDB\n */\nexport async function fetchDynamoDBMetrics(\n region: string,\n tableName: string,\n timeRange: { start: Date; end: Date }\n): Promise<DynamoDBMetrics> {\n const dynamodb = new DynamoDBClient({ region });\n\n try {\n const startTime = timeRange.start.getTime();\n const endTime = timeRange.end.getTime();\n\n // Scan the table for events in the time range\n // Note: In production, consider using accountId GSI for better performance\n const response = await dynamodb.send(\n new ScanCommand({\n TableName: tableName,\n FilterExpression:\n \"sentAt BETWEEN :startTime AND :endTime AND (eventType = :open OR eventType = :click)\",\n ExpressionAttributeValues: {\n \":startTime\": { N: startTime.toString() },\n \":endTime\": { N: endTime.toString() },\n \":open\": { S: \"Open\" },\n \":click\": { S: \"Click\" },\n },\n })\n );\n\n const items = (response.Items || []).map((item) => unmarshall(item));\n\n // Group events by 5-minute buckets (to match CloudWatch period)\n const period = 5 * 60 * 1000; // 5 minutes in milliseconds\n const openBuckets = new Map<number, number>();\n const clickBuckets = new Map<number, number>();\n\n for (const item of items) {\n const timestamp = Number(item.sentAt);\n const bucket = Math.floor(timestamp / period) * period;\n const eventType = item.eventType;\n\n if (eventType === \"Open\") {\n openBuckets.set(bucket, (openBuckets.get(bucket) || 0) + 1);\n } else if (eventType === \"Click\") {\n clickBuckets.set(bucket, (clickBuckets.get(bucket) || 0) + 1);\n }\n }\n\n // Convert to array format\n const opens = Array.from(openBuckets.entries()).map(\n ([timestamp, value]) => ({\n timestamp,\n value,\n })\n );\n\n const clicks = Array.from(clickBuckets.entries()).map(\n ([timestamp, value]) => ({\n timestamp,\n value,\n })\n );\n\n return {\n opens: opens.sort((a, b) => a.timestamp - b.timestamp),\n clicks: clicks.sort((a, b) => a.timestamp - b.timestamp),\n };\n } catch (error) {\n console.error(\"Error fetching DynamoDB metrics:\", error);\n // Return empty arrays on error instead of throwing\n return {\n opens: [],\n clicks: [],\n };\n }\n}\n","#!/usr/bin/env node\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as clack from \"@clack/prompts\";\nimport args from \"args\";\nimport pc from \"picocolors\";\n// Dashboard commands\nimport { updateRole } from \"./commands/dashboard/update-role.js\";\nimport { config } from \"./commands/email/config.js\";\n// Email commands\nimport { connect } from \"./commands/email/connect.js\";\nimport { emailDestroy } from \"./commands/email/destroy.js\";\nimport {\n addDomain,\n getDkim,\n listDomains,\n removeDomain,\n verifyDomain,\n} from \"./commands/email/domains.js\";\nimport { init } from \"./commands/email/init.js\";\nimport { restore } from \"./commands/email/restore.js\";\nimport { emailStatus } from \"./commands/email/status.js\";\nimport { upgrade } from \"./commands/email/upgrade.js\";\n// Shared commands\nimport { dashboard } from \"./commands/shared/dashboard.js\";\nimport { destroy } from \"./commands/shared/destroy.js\";\nimport { status } from \"./commands/shared/status.js\";\n// SMS commands\nimport { smsDestroy } from \"./commands/sms/destroy.js\";\nimport { init as smsInit } from \"./commands/sms/init.js\";\nimport { smsRegister } from \"./commands/sms/register.js\";\nimport { smsStatus } from \"./commands/sms/status.js\";\nimport { smsSync } from \"./commands/sms/sync.js\";\nimport { smsTest } from \"./commands/sms/test.js\";\nimport { smsUpgrade } from \"./commands/sms/upgrade.js\";\nimport { smsVerifyNumber } from \"./commands/sms/verify-number.js\";\n// Telemetry commands\nimport {\n telemetryDisable,\n telemetryEnable,\n telemetryStatus,\n} from \"./commands/telemetry.js\";\nimport { getTelemetryClient } from \"./telemetry/client.js\";\nimport { trackCommand } from \"./telemetry/events.js\";\nimport {\n printCompletionScript,\n setupTabCompletion,\n} from \"./utils/shared/completion.js\";\nimport { handleCLIError } from \"./utils/shared/errors.js\";\n\n// Get package version\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst packageJson = JSON.parse(\n readFileSync(join(__dirname, \"../package.json\"), \"utf-8\")\n);\nconst VERSION = packageJson.version;\n\n// Setup tab completion\nsetupTabCompletion();\n\n// Function to show version\nfunction showVersion() {\n console.log(`wraps v${VERSION}`);\n process.exit(0);\n}\n\n// Function to show help\nfunction showHelp() {\n clack.intro(pc.bold(`WRAPS CLI v${VERSION}`));\n console.log(\"Deploy AWS infrastructure to your account\\n\");\n console.log(\"Usage: wraps [service] <command> [options]\\n\");\n console.log(\"Services:\");\n console.log(` ${pc.cyan(\"email\")} Email infrastructure (AWS SES)`);\n console.log(\n ` ${pc.cyan(\"sms\")} SMS infrastructure (AWS End User Messaging)\\n`\n );\n console.log(\"Email Commands:\");\n console.log(\n ` ${pc.cyan(\"email init\")} Deploy new email infrastructure`\n );\n console.log(\n ` ${pc.cyan(\"email connect\")} Connect to existing AWS SES`\n );\n console.log(\n ` ${pc.cyan(\"email status\")} Show email infrastructure details`\n );\n console.log(` ${pc.cyan(\"email verify\")} Verify domain DNS records`);\n console.log(\n ` ${pc.cyan(\"email sync\")} Apply CLI updates to infrastructure`\n );\n console.log(` ${pc.cyan(\"email upgrade\")} Add features`);\n console.log(\n ` ${pc.cyan(\"email restore\")} Restore original configuration`\n );\n console.log(\n ` ${pc.cyan(\"email destroy\")} Remove email infrastructure`\n );\n console.log(` ${pc.cyan(\"email domains add\")} Add a domain to SES`);\n console.log(` ${pc.cyan(\"email domains list\")} List all domains`);\n console.log(` ${pc.cyan(\"email domains remove\")} Remove a domain\\n`);\n console.log(\"SMS Commands:\");\n console.log(` ${pc.cyan(\"sms init\")} Deploy SMS infrastructure`);\n console.log(\n ` ${pc.cyan(\"sms status\")} Show SMS infrastructure details`\n );\n console.log(` ${pc.cyan(\"sms test\")} Send a test SMS message`);\n console.log(\n ` ${pc.cyan(\"sms verify-number\")} Verify a destination phone number`\n );\n console.log(\n ` ${pc.cyan(\"sms sync\")} Sync infrastructure (update Lambda, etc.)`\n );\n console.log(` ${pc.cyan(\"sms upgrade\")} Upgrade SMS features`);\n console.log(` ${pc.cyan(\"sms register\")} Register toll-free number`);\n console.log(\n ` ${pc.cyan(\"sms destroy\")} Remove SMS infrastructure\\n`\n );\n console.log(\"Console & Dashboard:\");\n console.log(` ${pc.cyan(\"console\")} Start local web console`);\n console.log(\n ` ${pc.cyan(\"dashboard update-role\")} Update hosted dashboard IAM permissions\\n`\n );\n console.log(\"Global Commands:\");\n console.log(` ${pc.cyan(\"status\")} Show overview of all services`);\n console.log(` ${pc.cyan(\"destroy\")} Remove deployed infrastructure`);\n console.log(` ${pc.cyan(\"completion\")} Generate shell completion script`);\n console.log(\n ` ${pc.cyan(\"telemetry\")} Manage anonymous telemetry settings\\n`\n );\n console.log(\"Options:\");\n console.log(\n ` ${pc.dim(\"-p, --provider\")} Hosting provider (vercel, aws, railway, other)`\n );\n console.log(` ${pc.dim(\"-r, --region\")} AWS region`);\n console.log(` ${pc.dim(\"-d, --domain\")} Domain name`);\n console.log(` ${pc.dim(\"--account\")} AWS account ID or alias`);\n console.log(` ${pc.dim(\"--preset\")} Configuration preset`);\n console.log(` ${pc.dim(\"-y, --yes\")} Skip confirmation prompts`);\n console.log(` ${pc.dim(\"-f, --force\")} Force destructive operations`);\n console.log(\n ` ${pc.dim(\"--preview\")} Preview changes without deploying`\n );\n console.log(` ${pc.dim(\"-v, --version\")} Show version number\\n`);\n console.log(\n `Run ${pc.cyan(\"wraps <service> <command> --help\")} for more information.\\n`\n );\n process.exit(0);\n}\n\n// Check for version before args parses\nif (process.argv.includes(\"--version\") || process.argv.includes(\"-v\")) {\n showVersion();\n}\n\n// Check for help before args parses (to override args' built-in help)\nif (process.argv.includes(\"--help\") || process.argv.includes(\"-h\")) {\n showHelp();\n}\n\n// Configure args\nargs.options([\n {\n name: [\"p\", \"provider\"],\n description: \"Hosting provider (vercel, aws, railway, other)\",\n defaultValue: undefined,\n },\n {\n name: [\"r\", \"region\"],\n description: \"AWS region\",\n defaultValue: undefined,\n },\n {\n name: [\"d\", \"domain\"],\n description: \"Domain name\",\n defaultValue: undefined,\n },\n {\n name: \"account\",\n description: \"AWS account ID or alias\",\n defaultValue: undefined,\n },\n {\n name: \"preset\",\n description:\n \"Configuration preset (starter, production, enterprise, custom)\",\n defaultValue: undefined,\n },\n {\n name: [\"y\", \"yes\"],\n description: \"Skip confirmation prompts (non-destructive operations)\",\n defaultValue: false,\n },\n {\n name: [\"f\", \"force\"],\n description:\n \"Force operation without confirmation (destructive operations)\",\n defaultValue: false,\n },\n {\n name: \"port\",\n description: \"Port for dashboard server\",\n defaultValue: undefined,\n },\n {\n name: \"noOpen\",\n description: \"Don't open browser automatically\",\n defaultValue: false,\n },\n {\n name: \"preview\",\n description: \"Preview changes without deploying\",\n defaultValue: false,\n },\n // SMS-specific options\n {\n name: \"to\",\n description: \"Destination phone number (E.164 format)\",\n defaultValue: undefined,\n },\n {\n name: \"message\",\n description: \"SMS message content\",\n defaultValue: undefined,\n },\n // SMS verify-number options\n {\n name: \"phoneNumber\",\n description: \"Phone number to verify (E.164 format)\",\n defaultValue: undefined,\n },\n {\n name: \"code\",\n description: \"Verification code received via SMS\",\n defaultValue: undefined,\n },\n {\n name: \"list\",\n description: \"List all verified destination numbers\",\n defaultValue: false,\n },\n {\n name: \"delete\",\n description: \"Delete a verified destination number\",\n defaultValue: false,\n },\n {\n name: \"resend\",\n description: \"Resend verification code\",\n defaultValue: false,\n },\n]);\n\n// Get command and flags\nconst flags = args.parse(process.argv);\nconst [primaryCommand, subCommand] = args.sub;\n\n// If no command provided, show interactive service selection\nif (!primaryCommand) {\n async function selectService() {\n clack.intro(pc.bold(`WRAPS CLI v${VERSION}`));\n console.log(\n \"Welcome! Let's get started deploying your email infrastructure.\\n\"\n );\n\n // Ask what action they want to take\n const action = await clack.select({\n message: \"What would you like to do?\",\n options: [\n {\n value: \"init\",\n label: \"Deploy new infrastructure\",\n hint: \"Create new AWS SES infrastructure\",\n },\n {\n value: \"connect\",\n label: \"Connect existing infrastructure\",\n hint: \"Connect to existing AWS SES setup\",\n },\n ],\n });\n\n if (clack.isCancel(action)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n // Run the appropriate command\n if (action === \"init\") {\n await init({\n provider: flags.provider,\n region: flags.region,\n domain: flags.domain,\n preset: flags.preset,\n yes: flags.yes,\n preview: flags.preview,\n });\n } else {\n await connect({\n provider: flags.provider,\n region: flags.region,\n yes: flags.yes,\n preview: flags.preview,\n });\n }\n }\n\n selectService().catch(handleCLIError);\n // Early exit - don't run the main run() function\n process.exit(0);\n}\n\n// Route to appropriate command\nasync function run() {\n const startTime = Date.now();\n const telemetry = getTelemetryClient();\n\n // Show first-run telemetry notification\n if (telemetry.shouldShowNotification()) {\n console.log();\n clack.log.info(pc.bold(\"Anonymous Telemetry\"));\n console.log(\n ` Wraps collects ${pc.cyan(\"anonymous usage data\")} to improve the CLI.`\n );\n console.log(\n ` We ${pc.bold(\"never\")} collect: domains, AWS credentials, email content, or PII.`\n );\n console.log(\n ` We ${pc.bold(\"only\")} collect: command names, success/failure, CLI version, OS.`\n );\n console.log();\n console.log(` Opt-out anytime: ${pc.cyan(\"wraps telemetry disable\")}`);\n console.log(` Or set: ${pc.cyan(\"WRAPS_TELEMETRY_DISABLED=1\")}`);\n console.log(` Learn more: ${pc.cyan(\"https://wraps.dev/docs/telemetry\")}`);\n console.log();\n\n telemetry.markNotificationShown();\n }\n\n try {\n // Handle service-specific subcommands (e.g., wraps email init)\n if (primaryCommand === \"email\" && subCommand) {\n switch (subCommand) {\n case \"init\":\n await init({\n provider: flags.provider,\n region: flags.region,\n domain: flags.domain,\n preset: flags.preset,\n yes: flags.yes,\n preview: flags.preview,\n });\n break;\n\n case \"connect\":\n await connect({\n provider: flags.provider,\n region: flags.region,\n yes: flags.yes,\n preview: flags.preview,\n });\n break;\n\n case \"config\":\n case \"sync\":\n await config({\n region: flags.region,\n yes: flags.yes,\n preview: flags.preview,\n });\n break;\n\n case \"upgrade\":\n await upgrade({\n region: flags.region,\n yes: flags.yes,\n preview: flags.preview,\n });\n break;\n\n case \"restore\":\n await restore({\n region: flags.region,\n force: flags.force,\n preview: flags.preview,\n });\n break;\n\n case \"status\":\n await emailStatus({\n account: flags.account,\n region: flags.region,\n });\n break;\n\n case \"verify\": {\n if (!flags.domain) {\n clack.log.error(\"--domain flag is required\");\n console.log(\n `\\nUsage: ${pc.cyan(\"wraps email verify --domain yourapp.com\")}\\n`\n );\n process.exit(1);\n }\n await verifyDomain({ domain: flags.domain });\n break;\n }\n\n case \"domains\": {\n // Handle domains subcommands\n const domainsSubCommand = args.sub[2];\n\n switch (domainsSubCommand) {\n case \"add\": {\n if (!flags.domain) {\n clack.log.error(\"--domain flag is required\");\n console.log(\n `\\nUsage: ${pc.cyan(\"wraps email domains add --domain yourapp.com\")}\\n`\n );\n process.exit(1);\n }\n await addDomain({ domain: flags.domain });\n break;\n }\n\n case \"list\":\n await listDomains();\n break;\n\n case \"verify\": {\n if (!flags.domain) {\n clack.log.error(\"--domain flag is required\");\n console.log(\n `\\nUsage: ${pc.cyan(\"wraps email domains verify --domain yourapp.com\")}\\n`\n );\n process.exit(1);\n }\n await verifyDomain({ domain: flags.domain });\n break;\n }\n\n case \"get-dkim\": {\n if (!flags.domain) {\n clack.log.error(\"--domain flag is required\");\n console.log(\n `\\nUsage: ${pc.cyan(\"wraps email domains get-dkim --domain yourapp.com\")}\\n`\n );\n process.exit(1);\n }\n await getDkim({ domain: flags.domain });\n break;\n }\n\n case \"remove\": {\n if (!flags.domain) {\n clack.log.error(\"--domain flag is required\");\n console.log(\n `\\nUsage: ${pc.cyan(\"wraps email domains remove --domain yourapp.com --force\")}\\n`\n );\n process.exit(1);\n }\n await removeDomain({\n domain: flags.domain,\n force: flags.force,\n });\n break;\n }\n\n default:\n clack.log.error(\n `Unknown domains command: ${domainsSubCommand || \"(none)\"}`\n );\n console.log(\n `\\nAvailable commands: ${pc.cyan(\"add\")}, ${pc.cyan(\"list\")}, ${pc.cyan(\"verify\")}, ${pc.cyan(\"get-dkim\")}, ${pc.cyan(\"remove\")}\\n`\n );\n process.exit(1);\n }\n break;\n }\n\n case \"destroy\":\n await emailDestroy({\n force: flags.force,\n region: flags.region,\n preview: flags.preview,\n });\n break;\n\n default:\n clack.log.error(`Unknown email command: ${subCommand}`);\n console.log(\n `\\nRun ${pc.cyan(\"wraps --help\")} for available commands.\\n`\n );\n process.exit(1);\n }\n // Track email commands (they return early, so track here)\n const emailDuration = Date.now() - startTime;\n const emailCommandName = `email:${subCommand}`;\n trackCommand(emailCommandName, {\n success: true,\n duration_ms: emailDuration,\n service: \"email\",\n });\n return;\n }\n\n // Handle SMS subcommands (e.g., wraps sms init)\n if (primaryCommand === \"sms\" && subCommand) {\n switch (subCommand) {\n case \"init\":\n await smsInit({\n provider: flags.provider,\n region: flags.region,\n preset: flags.preset,\n yes: flags.yes,\n });\n break;\n\n case \"status\":\n await smsStatus({\n account: flags.account,\n });\n break;\n\n case \"test\":\n await smsTest({\n to: flags.to,\n message: flags.message,\n });\n break;\n\n case \"upgrade\":\n await smsUpgrade({\n region: flags.region,\n yes: flags.yes,\n });\n break;\n\n case \"sync\":\n await smsSync({\n region: flags.region,\n yes: flags.yes,\n });\n break;\n\n case \"destroy\":\n await smsDestroy({\n force: flags.force,\n preview: flags.preview,\n });\n break;\n\n case \"verify-number\":\n await smsVerifyNumber({\n phoneNumber: flags.phoneNumber,\n code: flags.code,\n list: flags.list,\n delete: flags.delete,\n resend: flags.resend,\n });\n break;\n\n case \"register\":\n await smsRegister({\n region: flags.region,\n });\n break;\n\n default:\n clack.log.error(`Unknown sms command: ${subCommand}`);\n console.log(\n `\\nRun ${pc.cyan(\"wraps --help\")} for available commands.\\n`\n );\n process.exit(1);\n }\n // Track SMS commands\n const smsDuration = Date.now() - startTime;\n const smsCommandName = `sms:${subCommand}`;\n trackCommand(smsCommandName, {\n success: true,\n duration_ms: smsDuration,\n service: \"sms\",\n });\n return;\n }\n\n // Handle Dashboard subcommands\n if (primaryCommand === \"dashboard\" && subCommand) {\n switch (subCommand) {\n case \"update-role\":\n await updateRole({\n region: flags.region,\n force: flags.force,\n });\n break;\n\n default:\n clack.log.error(`Unknown dashboard command: ${subCommand}`);\n console.log(`\\nAvailable commands: ${pc.cyan(\"update-role\")}\\n`);\n console.log(`Run ${pc.cyan(\"wraps --help\")} for more information.\\n`);\n process.exit(1);\n }\n // Track dashboard commands (they return early, so track here)\n const dashboardDuration = Date.now() - startTime;\n const dashboardCommandName = `dashboard:${subCommand}`;\n trackCommand(dashboardCommandName, {\n success: true,\n duration_ms: dashboardDuration,\n });\n return;\n }\n\n // Handle global commands\n switch (primaryCommand) {\n // Global commands (work across all services)\n case \"status\":\n await status({\n account: flags.account,\n });\n break;\n\n case \"console\":\n await dashboard({\n port: flags.port,\n noOpen: flags.noOpen,\n });\n break;\n\n case \"dashboard\":\n // Deprecated: 'wraps dashboard' without subcommand redirects to 'wraps console'\n if (!subCommand) {\n clack.log.warn(\n `'wraps dashboard' is deprecated. Use ${pc.cyan(\"wraps console\")} instead.`\n );\n await dashboard({\n port: flags.port,\n noOpen: flags.noOpen,\n });\n }\n break;\n\n case \"destroy\":\n await destroy({\n force: flags.force,\n preview: flags.preview,\n });\n break;\n\n case \"completion\":\n printCompletionScript();\n break;\n\n case \"telemetry\": {\n // Handle telemetry subcommands\n switch (subCommand) {\n case \"enable\":\n await telemetryEnable();\n break;\n\n case \"disable\":\n await telemetryDisable();\n break;\n\n case \"status\":\n case undefined:\n await telemetryStatus();\n break;\n\n default:\n clack.log.error(`Unknown telemetry command: ${subCommand}`);\n console.log(\n `\\nAvailable commands: ${pc.cyan(\"enable\")}, ${pc.cyan(\"disable\")}, ${pc.cyan(\"status\")}\\n`\n );\n process.exit(1);\n }\n break;\n }\n\n // Show help for service without subcommand\n case \"email\":\n case \"sms\":\n console.log(\n `\\nPlease specify a command for ${primaryCommand} service.\\n`\n );\n showHelp();\n break;\n\n default:\n clack.log.error(`Unknown command: ${primaryCommand}`);\n console.log(\n `\\nRun ${pc.cyan(\"wraps --help\")} for available commands.\\n`\n );\n process.exit(1);\n }\n // Track successful command execution\n const duration = Date.now() - startTime;\n const commandName = subCommand\n ? `${primaryCommand}:${subCommand}`\n : primaryCommand;\n\n trackCommand(commandName, {\n success: true,\n duration_ms: duration,\n });\n } catch (error) {\n // Track failed command execution\n const duration = Date.now() - startTime;\n const commandName = subCommand\n ? `${primaryCommand}:${subCommand}`\n : primaryCommand;\n\n trackCommand(commandName, {\n success: false,\n duration_ms: duration,\n });\n\n handleCLIError(error);\n } finally {\n // Ensure telemetry events are sent before exit\n await telemetry.shutdown();\n }\n}\n\nrun();\n","import { GetRoleCommand, IAMClient } from \"@aws-sdk/client-iam\";\nimport { confirm, intro, isCancel, log, outro } from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport type { UpdateRoleOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { loadConnectionMetadata } from \"../../utils/shared/metadata.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\n\n/**\n * Update hosted dashboard access role command\n *\n * Updates the wraps-console-access-role IAM role with the latest permissions\n * needed for feature detection in the hosted dashboard app (e.g., dynamodb:DescribeTable).\n *\n * This role is created when you connect AWS accounts through the hosted dashboard.\n * This command updates its permissions to match your current infrastructure setup.\n *\n * This command:\n * - Only updates the role if it exists (does not create it)\n * - Updates inline policies to match current feature requirements\n * - Preserves the trust policy (AssumeRole configuration)\n */\nexport async function updateRole(options: UpdateRoleOptions): Promise<void> {\n intro(pc.bold(\"Update Hosted Dashboard Access Role\"));\n\n const progress = new DeploymentProgress();\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region\n const region = options.region || (await getAWSRegion());\n\n // 3. Load metadata to check if deployment exists\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n if (!metadata) {\n progress.stop();\n log.error(\n `No Wraps deployment found for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n console.log(\n `\\nRun ${pc.cyan(\"wraps email init\")} to deploy infrastructure first.\\n`\n );\n process.exit(1);\n }\n\n // 4. Check if wraps-console-access-role exists\n const roleName = \"wraps-console-access-role\";\n const iam = new IAMClient({ region: \"us-east-1\" }); // IAM is global\n\n let roleExists = false;\n try {\n await iam.send(new GetRoleCommand({ RoleName: roleName }));\n roleExists = true;\n } catch (error) {\n if (\n error &&\n typeof error === \"object\" &&\n \"name\" in error &&\n error.name !== \"NoSuchEntity\"\n ) {\n throw error;\n }\n }\n\n if (!roleExists) {\n progress.stop();\n log.warn(`IAM role ${pc.cyan(roleName)} does not exist`);\n console.log(\n \"\\nThis role is created when you connect AWS accounts through the hosted dashboard.\"\n );\n console.log(\n \"If you haven't connected an AWS account to the hosted dashboard yet, there's nothing to update.\\n\"\n );\n process.exit(0);\n }\n\n progress.info(`Found IAM role: ${pc.cyan(roleName)}`);\n\n // 5. Confirm update (unless --force)\n if (!options.force) {\n progress.stop();\n const shouldContinue = await confirm({\n message: `Update IAM role ${pc.cyan(roleName)} with latest permissions?`,\n initialValue: true,\n });\n\n if (isCancel(shouldContinue) || !shouldContinue) {\n outro(\"Update cancelled\");\n process.exit(0);\n }\n }\n\n // 6. Build updated policy\n const emailConfig = metadata.services.email?.config;\n const smsConfig = metadata.services.sms?.config;\n const policy = buildConsolePolicyDocument(emailConfig, smsConfig);\n\n // Extract config values for display\n const sendingEnabled =\n !emailConfig ||\n (emailConfig.sendingEnabled as boolean | undefined) !== false;\n const eventTracking = emailConfig?.eventTracking as\n | Record<string, unknown>\n | undefined;\n const emailArchiving = emailConfig?.emailArchiving as\n | Record<string, unknown>\n | undefined;\n const smsEnabled = !!smsConfig;\n const smsSendingEnabled =\n smsConfig && (smsConfig.sendingEnabled as boolean | undefined) !== false;\n const smsEventTracking = smsConfig?.eventTracking as\n | Record<string, unknown>\n | undefined;\n\n // 7. Update role policy\n await progress.execute(\"Updating IAM role permissions\", async () => {\n const { PutRolePolicyCommand } = await import(\"@aws-sdk/client-iam\");\n\n await iam.send(\n new PutRolePolicyCommand({\n RoleName: roleName,\n PolicyName: \"wraps-console-access-policy\",\n PolicyDocument: JSON.stringify(policy, null, 2),\n })\n );\n });\n\n progress.stop();\n\n // Success\n outro(pc.green(\"✓ Hosted dashboard access role updated successfully\"));\n\n console.log(`\\n${pc.bold(\"Updated Permissions:\")}`);\n\n // Email permissions\n console.log(`\\n ${pc.bold(pc.cyan(\"Email:\"))}`);\n console.log(\n ` ${pc.green(\"✓\")} SES metrics and identity verification (always enabled)`\n );\n console.log(` ${pc.green(\"✓\")} SES template management (always enabled)`);\n\n if (sendingEnabled) {\n console.log(` ${pc.green(\"✓\")} Email sending via SES`);\n }\n\n if (eventTracking?.dynamoDBHistory) {\n console.log(\n ` ${pc.green(\"✓\")} DynamoDB read access (including DescribeTable)`\n );\n }\n\n if (eventTracking?.enabled) {\n console.log(` ${pc.green(\"✓\")} EventBridge and SQS access`);\n }\n\n if (emailArchiving?.enabled) {\n console.log(` ${pc.green(\"✓\")} Mail Manager Archive access`);\n }\n\n // SMS permissions\n if (smsEnabled) {\n console.log(`\\n ${pc.bold(pc.cyan(\"SMS:\"))}`);\n console.log(\n ` ${pc.green(\"✓\")} SMS Voice V2 read access (phone numbers, config, registrations)`\n );\n\n if (smsSendingEnabled) {\n console.log(` ${pc.green(\"✓\")} SMS sending via SMS Voice V2`);\n }\n\n if (smsEventTracking?.dynamoDBHistory) {\n console.log(` ${pc.green(\"✓\")} DynamoDB read access for SMS history`);\n }\n\n if (smsEventTracking?.enabled) {\n console.log(` ${pc.green(\"✓\")} SNS topic access for SMS events`);\n }\n }\n\n console.log(\n `\\n${pc.dim(\"The hosted dashboard will now have updated permissions for feature detection.\")}\\n`\n );\n}\n\n/**\n * Build IAM policy document for hosted dashboard access role\n *\n * This mirrors the permissions from the main wraps-email-role and wraps-sms-role\n * but is used for the hosted dashboard app (not for SDK sending or local console).\n */\ntype PolicyStatement = {\n Effect: string;\n Action: string[];\n Resource: string | string[];\n};\n\ntype PolicyDocument = {\n Version: string;\n Statement: PolicyStatement[];\n};\n\nfunction buildConsolePolicyDocument(\n emailConfig: Record<string, unknown> | undefined,\n smsConfig?: Record<string, unknown> | undefined\n): PolicyDocument {\n const statements: PolicyStatement[] = [];\n\n // ========== EMAIL PERMISSIONS ==========\n\n // Always allow reading SES metrics for dashboard\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"ses:GetSendStatistics\",\n \"ses:ListIdentities\",\n \"ses:GetIdentityVerificationAttributes\",\n \"cloudwatch:GetMetricData\",\n \"cloudwatch:GetMetricStatistics\",\n ],\n Resource: \"*\",\n });\n\n // Always allow SES template management (for publishing email templates)\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"ses:GetTemplate\",\n \"ses:ListTemplates\",\n \"ses:CreateTemplate\",\n \"ses:UpdateTemplate\",\n \"ses:DeleteTemplate\",\n \"ses:TestRenderTemplate\",\n ],\n Resource: \"*\",\n });\n\n // Allow sending if enabled\n const sendingEnabled = !emailConfig || emailConfig.sendingEnabled !== false;\n if (sendingEnabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"ses:SendEmail\",\n \"ses:SendRawEmail\",\n \"ses:SendTemplatedEmail\",\n \"ses:SendBulkTemplatedEmail\",\n ],\n Resource: \"*\",\n });\n }\n\n // Allow DynamoDB access if history storage enabled\n const eventTracking = emailConfig?.eventTracking as\n | Record<string, unknown>\n | undefined;\n if (eventTracking?.dynamoDBHistory) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"dynamodb:PutItem\",\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n \"dynamodb:Scan\",\n \"dynamodb:BatchGetItem\",\n \"dynamodb:DescribeTable\",\n ],\n Resource: [\n \"arn:aws:dynamodb:*:*:table/wraps-email-*\",\n \"arn:aws:dynamodb:*:*:table/wraps-email-*/index/*\",\n ],\n });\n }\n\n // Allow EventBridge access if event tracking enabled\n if (eventTracking?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\"events:PutEvents\", \"events:DescribeEventBus\"],\n Resource: \"arn:aws:events:*:*:event-bus/wraps-email-*\",\n });\n }\n\n // Allow SQS access if event tracking enabled\n if (eventTracking?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"sqs:SendMessage\",\n \"sqs:ReceiveMessage\",\n \"sqs:DeleteMessage\",\n \"sqs:GetQueueAttributes\",\n ],\n Resource: \"arn:aws:sqs:*:*:wraps-email-*\",\n });\n }\n\n // Allow Mail Manager Archive access if email archiving enabled\n const emailArchiving = emailConfig?.emailArchiving as\n | Record<string, unknown>\n | undefined;\n if (emailArchiving?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"ses:StartArchiveSearch\",\n \"ses:GetArchiveSearchResults\",\n \"ses:GetArchiveMessage\",\n \"ses:GetArchiveMessageContent\",\n \"ses:GetArchive\",\n \"ses:ListArchives\",\n \"ses:StartArchiveExport\",\n \"ses:GetArchiveExport\",\n ],\n Resource: \"arn:aws:ses:*:*:mailmanager-archive/*\",\n });\n }\n\n // ========== SMS PERMISSIONS ==========\n\n if (smsConfig) {\n // Always allow reading SMS metrics and config for dashboard\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"sms-voice:DescribeAccountAttributes\",\n \"sms-voice:DescribeSpendLimits\",\n \"sms-voice:DescribeConfigurationSets\",\n \"sms-voice:DescribeOptOutLists\",\n \"sms-voice:DescribeOptedOutNumbers\",\n \"sms-voice:DescribePools\",\n \"sms-voice:DescribePhoneNumbers\",\n \"sms-voice:DescribeProtectConfigurations\",\n \"sms-voice:DescribeRegistrations\",\n \"sms-voice:DescribeRegistrationAttachments\",\n \"sms-voice:DescribeRegistrationFieldDefinitions\",\n \"sms-voice:DescribeRegistrationFieldValues\",\n \"sms-voice:DescribeRegistrationSectionDefinitions\",\n \"sms-voice:DescribeRegistrationVersions\",\n ],\n Resource: \"*\",\n });\n\n // Allow SMS sending if enabled\n const smsSendingEnabled = smsConfig.sendingEnabled !== false;\n if (smsSendingEnabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\"sms-voice:SendTextMessage\", \"sms-voice:SendMediaMessage\"],\n Resource: \"*\",\n });\n }\n\n // Allow DynamoDB access for SMS history if enabled\n const smsEventTracking = smsConfig.eventTracking as\n | Record<string, unknown>\n | undefined;\n if (smsEventTracking?.dynamoDBHistory) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n \"dynamodb:Scan\",\n \"dynamodb:BatchGetItem\",\n \"dynamodb:DescribeTable\",\n ],\n Resource: [\n \"arn:aws:dynamodb:*:*:table/wraps-sms-*\",\n \"arn:aws:dynamodb:*:*:table/wraps-sms-*/index/*\",\n ],\n });\n }\n\n // Allow SNS access for SMS events if enabled\n if (smsEventTracking?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\"sns:GetTopicAttributes\", \"sns:ListSubscriptionsByTopic\"],\n Resource: \"arn:aws:sns:*:*:wraps-sms-*\",\n });\n }\n }\n\n return {\n Version: \"2012-10-17\",\n Statement: statements,\n };\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type {\n EmailConfigPreset,\n Provider,\n ServiceType,\n SMSConfigPreset,\n WrapsEmailConfig,\n WrapsSMSConfig,\n} from \"../../types/index.js\";\nimport { ensureWrapsDir, getWrapsDir } from \"./fs.js\";\n\n/**\n * Service-specific configuration with metadata\n */\nexport type ServiceConfig<TConfig, TPreset> = {\n preset?: TPreset;\n config: TConfig;\n pulumiStackName?: string;\n deployedAt: string;\n};\n\n/**\n * Connection metadata - supports multiple services per AWS account/region\n */\nexport type ConnectionMetadata = {\n version: string; // Metadata format version (e.g., \"1.0.0\")\n accountId: string;\n region: string;\n provider: Provider;\n timestamp: string; // Last updated timestamp\n vercel?: {\n teamSlug: string;\n projectName: string;\n };\n\n // Service-specific configurations\n services: {\n email?: ServiceConfig<WrapsEmailConfig, EmailConfigPreset>;\n sms?: ServiceConfig<WrapsSMSConfig, SMSConfigPreset>;\n };\n};\n\n/**\n * Legacy connection metadata (for backwards compatibility)\n * @deprecated Use ConnectionMetadata instead\n */\nexport type LegacyConnectionMetadata = {\n accountId: string;\n region: string;\n provider: Provider;\n timestamp: string;\n preset?: EmailConfigPreset;\n emailConfig: WrapsEmailConfig;\n vercel?: {\n teamSlug: string;\n projectName: string;\n };\n pulumiStackName?: string;\n};\n\n/**\n * Get the connections directory\n */\nfunction getConnectionsDir(): string {\n return join(getWrapsDir(), \"connections\");\n}\n\n/**\n * Get metadata file path for an account and region\n */\nfunction getMetadataPath(accountId: string, region: string): string {\n return join(getConnectionsDir(), `${accountId}-${region}.json`);\n}\n\n/**\n * Ensure the connections directory exists\n */\nasync function ensureConnectionsDir(): Promise<void> {\n await ensureWrapsDir();\n const connectionsDir = getConnectionsDir();\n if (!existsSync(connectionsDir)) {\n const { mkdir } = await import(\"node:fs/promises\");\n await mkdir(connectionsDir, { recursive: true });\n }\n}\n\n/**\n * Migrate legacy metadata to new multi-service format\n */\nfunction migrateLegacyMetadata(\n legacy: LegacyConnectionMetadata\n): ConnectionMetadata {\n return {\n version: \"1.0.0\",\n accountId: legacy.accountId,\n region: legacy.region,\n provider: legacy.provider,\n timestamp: legacy.timestamp,\n vercel: legacy.vercel,\n services: {\n email: {\n preset: legacy.preset,\n config: legacy.emailConfig,\n pulumiStackName: legacy.pulumiStackName,\n deployedAt: legacy.timestamp,\n },\n },\n };\n}\n\n/**\n * Check if metadata is in legacy format\n */\nfunction isLegacyMetadata(data: any): data is LegacyConnectionMetadata {\n return (\n \"emailConfig\" in data &&\n !(\"services\" in data) &&\n typeof data.emailConfig === \"object\"\n );\n}\n\n/**\n * Load connection metadata from disk\n * Automatically migrates legacy format to new multi-service format\n */\nexport async function loadConnectionMetadata(\n accountId: string,\n region: string\n): Promise<ConnectionMetadata | null> {\n const metadataPath = getMetadataPath(accountId, region);\n\n if (!existsSync(metadataPath)) {\n return null;\n }\n\n try {\n const content = await readFile(metadataPath, \"utf-8\");\n const data = JSON.parse(content);\n\n // Migrate legacy format if needed\n if (isLegacyMetadata(data)) {\n const migrated = migrateLegacyMetadata(data);\n // Save migrated version\n await saveConnectionMetadata(migrated);\n return migrated;\n }\n\n // Add version if missing (for backwards compatibility with early multi-service format)\n if (!data.version) {\n data.version = \"1.0.0\";\n await saveConnectionMetadata(data);\n }\n\n return data as ConnectionMetadata;\n } catch (error: any) {\n console.error(\"Error loading connection metadata:\", error.message);\n return null;\n }\n}\n\n/**\n * Save connection metadata to disk\n */\nexport async function saveConnectionMetadata(\n metadata: ConnectionMetadata\n): Promise<void> {\n await ensureConnectionsDir();\n const metadataPath = getMetadataPath(metadata.accountId, metadata.region);\n\n try {\n const content = JSON.stringify(metadata, null, 2);\n await writeFile(metadataPath, content, \"utf-8\");\n } catch (error: any) {\n console.error(\"Error saving connection metadata:\", error.message);\n throw error;\n }\n}\n\n/**\n * Delete connection metadata\n */\nexport async function deleteConnectionMetadata(\n accountId: string,\n region: string\n): Promise<void> {\n const metadataPath = getMetadataPath(accountId, region);\n\n if (existsSync(metadataPath)) {\n const { unlink } = await import(\"node:fs/promises\");\n await unlink(metadataPath);\n }\n}\n\n/**\n * List all connections\n */\nexport async function listConnections(): Promise<ConnectionMetadata[]> {\n const connectionsDir = getConnectionsDir();\n\n if (!existsSync(connectionsDir)) {\n return [];\n }\n\n try {\n const { readdir } = await import(\"node:fs/promises\");\n const files = await readdir(connectionsDir);\n const connections: ConnectionMetadata[] = [];\n\n for (const file of files) {\n if (file.endsWith(\".json\")) {\n const content = await readFile(join(connectionsDir, file), \"utf-8\");\n try {\n const metadata = JSON.parse(content) as ConnectionMetadata;\n connections.push(metadata);\n } catch (error) {\n console.error(`Error parsing ${file}:`, error);\n }\n }\n }\n\n return connections;\n } catch (error: any) {\n console.error(\"Error listing connections:\", error.message);\n return [];\n }\n}\n\n/**\n * Check if a connection exists\n */\nexport async function connectionExists(\n accountId: string,\n region: string\n): Promise<boolean> {\n const metadataPath = getMetadataPath(accountId, region);\n return existsSync(metadataPath);\n}\n\n/**\n * Create initial connection metadata\n * @deprecated Use addServiceToConnection instead\n */\nexport function createConnectionMetadata(\n accountId: string,\n region: string,\n provider: Provider,\n emailConfig: WrapsEmailConfig,\n preset?: EmailConfigPreset\n): ConnectionMetadata {\n return {\n version: \"1.0.0\",\n accountId,\n region,\n provider,\n timestamp: new Date().toISOString(),\n services: {\n email: {\n preset,\n config: emailConfig,\n deployedAt: new Date().toISOString(),\n },\n },\n };\n}\n\n/**\n * Apply config updates to existing config while preserving user-customized fields.\n *\n * This function starts with the existing config and applies updates,\n * while ensuring user-customized fields are never lost:\n * - domain (sending identity)\n * - mailFromDomain (custom MAIL FROM subdomain)\n * - tracking.customRedirectDomain (custom tracking domain)\n * - tracking.httpsEnabled (HTTPS tracking via CloudFront)\n */\nexport function applyConfigUpdates(\n existingConfig: WrapsEmailConfig,\n updates: Partial<WrapsEmailConfig>\n): WrapsEmailConfig {\n // Start with existing config (ensures all required fields are present)\n const result = { ...existingConfig };\n\n // Apply each update, with special handling for nested objects\n for (const [key, value] of Object.entries(updates)) {\n if (value === undefined) {\n continue;\n }\n\n if (key === \"tracking\" && typeof value === \"object\") {\n // Merge tracking updates while preserving user-customized fields\n const trackingUpdate = value as NonNullable<WrapsEmailConfig[\"tracking\"]>;\n result.tracking = {\n ...result.tracking,\n ...trackingUpdate,\n // Always preserve these if they exist in original\n customRedirectDomain:\n result.tracking?.customRedirectDomain ||\n trackingUpdate.customRedirectDomain,\n httpsEnabled:\n result.tracking?.httpsEnabled ?? trackingUpdate.httpsEnabled,\n };\n } else if (key === \"eventTracking\" && typeof value === \"object\") {\n // Deep merge eventTracking\n result.eventTracking = {\n ...result.eventTracking,\n ...(value as NonNullable<WrapsEmailConfig[\"eventTracking\"]>),\n } as NonNullable<WrapsEmailConfig[\"eventTracking\"]>;\n } else if (key === \"suppressionList\" && typeof value === \"object\") {\n // Deep merge suppressionList\n result.suppressionList = {\n ...result.suppressionList,\n ...(value as NonNullable<WrapsEmailConfig[\"suppressionList\"]>),\n } as NonNullable<WrapsEmailConfig[\"suppressionList\"]>;\n } else if (key === \"emailArchiving\" && typeof value === \"object\") {\n // Deep merge emailArchiving\n result.emailArchiving = {\n ...result.emailArchiving,\n ...(value as NonNullable<WrapsEmailConfig[\"emailArchiving\"]>),\n } as NonNullable<WrapsEmailConfig[\"emailArchiving\"]>;\n } else {\n // Direct assignment for primitives and other objects\n result[key as keyof WrapsEmailConfig] = value as any;\n }\n }\n\n return result;\n}\n\n/**\n * Update email configuration in metadata\n * @deprecated Use updateServiceConfig instead\n */\nexport function updateEmailConfig(\n metadata: ConnectionMetadata,\n emailConfig: Partial<WrapsEmailConfig>\n): void {\n if (!metadata.services.email) {\n throw new Error(\"Email service not configured in metadata\");\n }\n\n // Apply updates while preserving user-customized fields\n metadata.services.email.config = applyConfigUpdates(\n metadata.services.email.config,\n emailConfig\n );\n\n metadata.timestamp = new Date().toISOString();\n}\n\n/**\n * Add a service to an existing connection or create new connection metadata\n */\nexport function addServiceToConnection(\n accountId: string,\n region: string,\n provider: Provider,\n service: ServiceType,\n config: WrapsEmailConfig | WrapsSMSConfig,\n preset?: EmailConfigPreset | SMSConfigPreset,\n existingMetadata?: ConnectionMetadata\n): ConnectionMetadata {\n const timestamp = new Date().toISOString();\n\n if (existingMetadata) {\n // Add service to existing connection\n if (service === \"email\") {\n existingMetadata.services.email = {\n preset: preset as EmailConfigPreset,\n config: config as WrapsEmailConfig,\n deployedAt: timestamp,\n };\n } else if (service === \"sms\") {\n existingMetadata.services.sms = {\n preset: preset as SMSConfigPreset,\n config: config as WrapsSMSConfig,\n deployedAt: timestamp,\n };\n }\n existingMetadata.timestamp = timestamp;\n return existingMetadata;\n }\n\n // Create new connection metadata\n const metadata: ConnectionMetadata = {\n version: \"1.0.0\",\n accountId,\n region,\n provider,\n timestamp,\n services: {},\n };\n\n if (service === \"email\") {\n metadata.services.email = {\n preset: preset as EmailConfigPreset,\n config: config as WrapsEmailConfig,\n deployedAt: timestamp,\n };\n } else if (service === \"sms\") {\n metadata.services.sms = {\n preset: preset as SMSConfigPreset,\n config: config as WrapsSMSConfig,\n deployedAt: timestamp,\n };\n }\n\n return metadata;\n}\n\n/**\n * Update service configuration in metadata\n */\nexport function updateServiceConfig<T extends ServiceType>(\n metadata: ConnectionMetadata,\n service: T,\n config: T extends \"email\"\n ? Partial<WrapsEmailConfig>\n : T extends \"sms\"\n ? Partial<WrapsSMSConfig>\n : never\n): void {\n if (service === \"email\" && metadata.services.email) {\n metadata.services.email.config = {\n ...metadata.services.email.config,\n ...(config as Partial<WrapsEmailConfig>),\n };\n } else if (service === \"sms\" && metadata.services.sms) {\n metadata.services.sms.config = {\n ...metadata.services.sms.config,\n ...(config as Partial<WrapsSMSConfig>),\n };\n } else {\n throw new Error(`${service} service not configured in metadata`);\n }\n\n metadata.timestamp = new Date().toISOString();\n}\n\n/**\n * Remove a service from connection metadata\n */\nexport function removeServiceFromConnection(\n metadata: ConnectionMetadata,\n service: ServiceType\n): void {\n if (service === \"email\") {\n const { email, ...rest } = metadata.services;\n metadata.services = rest;\n } else if (service === \"sms\") {\n const { sms, ...rest } = metadata.services;\n metadata.services = rest;\n }\n metadata.timestamp = new Date().toISOString();\n}\n\n/**\n * Check if a service is configured in metadata\n */\nexport function hasService(\n metadata: ConnectionMetadata,\n service: ServiceType\n): boolean {\n if (service === \"email\") {\n return metadata.services.email !== undefined;\n }\n if (service === \"sms\") {\n return metadata.services.sms !== undefined;\n }\n return false;\n}\n\n/**\n * Get list of configured services in metadata\n */\nexport function getConfiguredServices(\n metadata: ConnectionMetadata\n): ServiceType[] {\n const services: ServiceType[] = [];\n if (metadata.services.email) {\n services.push(\"email\");\n }\n if (metadata.services.sms) {\n services.push(\"sms\");\n }\n return services;\n}\n\n/**\n * Find all connections for a specific AWS account\n * Useful for auto-detecting region when user doesn't specify one\n */\nexport async function findConnectionsForAccount(\n accountId: string\n): Promise<ConnectionMetadata[]> {\n const allConnections = await listConnections();\n return allConnections.filter((conn) => conn.accountId === accountId);\n}\n\n/**\n * Find connections for an account that have a specific service configured\n */\nexport async function findConnectionsWithService(\n accountId: string,\n service: ServiceType\n): Promise<ConnectionMetadata[]> {\n const accountConnections = await findConnectionsForAccount(accountId);\n return accountConnections.filter((conn) => hasService(conn, service));\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * Get the Wraps configuration directory\n */\nexport function getWrapsDir(): string {\n return join(homedir(), \".wraps\");\n}\n\n/**\n * Get the Pulumi workspace directory\n */\nexport function getPulumiWorkDir(): string {\n return join(getWrapsDir(), \"pulumi\");\n}\n\n/**\n * Ensure the Wraps configuration directory exists\n */\nexport async function ensureWrapsDir(): Promise<void> {\n const wrapsDir = getWrapsDir();\n if (!existsSync(wrapsDir)) {\n await mkdir(wrapsDir, { recursive: true });\n }\n}\n\n/**\n * Ensure the Pulumi workspace directory exists and configure local backend\n */\nexport async function ensurePulumiWorkDir(): Promise<void> {\n await ensureWrapsDir();\n const pulumiDir = getPulumiWorkDir();\n if (!existsSync(pulumiDir)) {\n await mkdir(pulumiDir, { recursive: true });\n }\n\n // Set Pulumi to use local backend (file-based state)\n // This avoids needing to login to Pulumi Cloud\n process.env.PULUMI_BACKEND_URL = `file://${pulumiDir}`;\n process.env.PULUMI_CONFIG_PASSPHRASE = \"\"; // Empty passphrase for simplicity\n}\n","import * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\n\n/**\n * Deployment progress tracker with spinners using clack\n */\nexport class DeploymentProgress {\n private currentSpinner: ReturnType<typeof clack.spinner> | null = null;\n\n /**\n * Start a spinner with a message\n */\n start(message: string) {\n this.currentSpinner = clack.spinner();\n this.currentSpinner.start(message);\n }\n\n /**\n * Mark current step as succeeded\n */\n succeed(message: string) {\n if (this.currentSpinner) {\n this.currentSpinner.stop(message);\n }\n clack.log.success(message);\n }\n\n /**\n * Mark current step as failed\n */\n fail(message: string) {\n if (this.currentSpinner) {\n this.currentSpinner.stop(message);\n }\n clack.log.error(message);\n }\n\n /**\n * Show info message\n */\n info(message: string) {\n clack.log.info(message);\n }\n\n /**\n * Show step message\n */\n step(message: string) {\n clack.log.step(message);\n }\n\n /**\n * Execute a step with automatic spinner handling\n */\n async execute<T>(message: string, fn: () => Promise<T>): Promise<T> {\n this.start(message);\n try {\n const result = await fn();\n this.succeed(message);\n return result;\n } catch (error) {\n this.fail(message);\n throw error;\n }\n }\n\n /**\n * Stop the spinner\n */\n stop(message?: string) {\n if (this.currentSpinner) {\n this.currentSpinner.stop(message || \"\");\n }\n }\n}\n\n/**\n * DNS record type\n */\nexport type DNSRecord = {\n name: string;\n type: string;\n value: string;\n};\n\n/**\n * Success output configuration\n */\nexport type SuccessOutputs = {\n roleArn: string;\n configSetName?: string;\n region: string;\n dnsRecords?: DNSRecord[];\n trackingDomainDnsRecords?: DNSRecord[];\n acmValidationRecords?: DNSRecord[];\n tableName?: string;\n dnsAutoCreated?: boolean;\n domain?: string;\n customTrackingDomain?: string;\n httpsTrackingEnabled?: boolean;\n mailFromDomain?: string;\n};\n\n/**\n * Display success message with infrastructure outputs\n */\nexport function displaySuccess(outputs: SuccessOutputs) {\n const lines = [\n \"\",\n pc.bold(\"Role ARN:\"),\n ` ${pc.cyan(outputs.roleArn)}`,\n \"\",\n `${pc.bold(\"Region:\")} ${pc.cyan(outputs.region)}`,\n ];\n\n if (outputs.configSetName) {\n lines.push(`${pc.bold(\"Config Set:\")} ${pc.cyan(outputs.configSetName)}`);\n }\n\n if (outputs.tableName) {\n lines.push(`${pc.bold(\"DynamoDB Table:\")} ${pc.cyan(outputs.tableName)}`);\n }\n\n lines.push(\n \"\",\n pc.bold(\"Next steps:\"),\n ` 1. Install SDK: ${pc.yellow(\"npm install @wraps/sdk\")}`,\n ` 2. View dashboard: ${pc.blue(\"https://app.wraps.dev\")}`,\n \"\"\n );\n\n clack.outro(pc.green(\"Email infrastructure deployed successfully!\"));\n console.log(lines.join(\"\\n\"));\n\n // Show DNS auto-creation message\n if (outputs.dnsAutoCreated && outputs.domain) {\n clack.note(\n `DNS records (DKIM, SPF, DMARC) were automatically created in Route53 for ${pc.cyan(\n outputs.domain\n )}.\\n\\nVerification should complete within a few minutes.`,\n pc.green(\"✓ DNS Auto-Configured\")\n );\n }\n\n if (outputs.dnsRecords && outputs.dnsRecords.length > 0) {\n // Extract domain from first DKIM record\n const domain = outputs.dnsRecords[0]?.name.split(\"._domainkey.\")[1];\n\n const dnsLines = [\n pc.bold(\"DKIM Records (CNAME):\"),\n ...outputs.dnsRecords.map(\n (record) =>\n ` ${pc.cyan(record.name)} ${pc.dim(record.type)} \"${record.value}\"`\n ),\n ];\n\n if (domain) {\n // Use MAIL FROM domain for DMARC rua if configured, otherwise use main domain\n const dmarcRuaDomain = outputs.mailFromDomain || domain;\n dnsLines.push(\n \"\",\n pc.bold(\"SPF Record (TXT):\"),\n ` ${pc.cyan(domain)} ${pc.dim(\"TXT\")} \"v=spf1 include:amazonses.com ~all\"`,\n pc.dim(\n \" Note: If you have an existing SPF record, add 'include:amazonses.com' to it\"\n ),\n \"\",\n pc.bold(\"DMARC Record (TXT):\"),\n ` ${pc.cyan(`_dmarc.${domain}`)} ${pc.dim(\"TXT\")} \"v=DMARC1; p=quarantine; rua=mailto:postmaster@${dmarcRuaDomain}\"`\n );\n\n // Add MAIL FROM domain DNS records if configured\n if (outputs.mailFromDomain) {\n dnsLines.push(\n \"\",\n pc.bold(\"MAIL FROM Domain Records (for DMARC alignment):\"),\n ` ${pc.cyan(outputs.mailFromDomain)} ${pc.dim(\"MX\")} \"10 feedback-smtp.${outputs.region}.amazonses.com\"`,\n ` ${pc.cyan(outputs.mailFromDomain)} ${pc.dim(\"TXT\")} \"v=spf1 include:amazonses.com ~all\"`\n );\n }\n }\n\n clack.note(dnsLines.join(\"\\n\"), \"DNS Records to add:\");\n }\n\n // Show ACM certificate validation records if HTTPS tracking is enabled\n if (outputs.acmValidationRecords && outputs.acmValidationRecords.length > 0) {\n const acmDnsLines = [\n pc.bold(\"SSL Certificate Validation (ACM):\"),\n ...outputs.acmValidationRecords.map(\n (record) =>\n ` ${pc.cyan(record.name)} ${pc.dim(record.type)} \"${record.value}\"`\n ),\n \"\",\n pc.dim(\n \"Note: These records are required to validate your SSL certificate.\"\n ),\n pc.dim(\n \"CloudFront will be enabled automatically after certificate validation.\"\n ),\n ];\n\n clack.note(\n acmDnsLines.join(\"\\n\"),\n \"SSL Certificate Validation DNS Records:\"\n );\n }\n\n // Show tracking domain DNS records if custom tracking domain is configured\n if (\n outputs.trackingDomainDnsRecords &&\n outputs.trackingDomainDnsRecords.length > 0\n ) {\n const trackingProtocol = outputs.httpsTrackingEnabled ? \"HTTPS\" : \"HTTP\";\n const trackingDnsLines = [\n pc.bold(`Custom Tracking Domain - ${trackingProtocol} Redirect CNAME:`),\n ...outputs.trackingDomainDnsRecords.map(\n (record) =>\n ` ${pc.cyan(record.name)} ${pc.dim(record.type)} \"${record.value}\"`\n ),\n \"\",\n pc.dim(\n \"Note: This CNAME allows SES to rewrite links in your emails to use\"\n ),\n pc.dim(\"your custom domain for open and click tracking.\"),\n ];\n\n if (outputs.httpsTrackingEnabled) {\n trackingDnsLines.push(\n \"\",\n pc.dim(\"HTTPS tracking is enabled via CloudFront with SSL certificate.\")\n );\n }\n\n clack.note(\n trackingDnsLines.join(\"\\n\"),\n \"Custom Tracking Domain DNS Records:\"\n );\n\n if (outputs.customTrackingDomain) {\n console.log(\n `\\n${pc.dim(\"Run:\")} ${pc.yellow(`wraps email verify --domain ${outputs.customTrackingDomain}`)} ${pc.dim(\n \"(after DNS propagates)\"\n )}\\n`\n );\n }\n }\n\n // Show tracking domain separately if we only have tracking domain (no other DNS records)\n // ONLY for HTTP tracking - HTTPS tracking DNS records are shown after CloudFront is created\n if (\n outputs.customTrackingDomain &&\n !outputs.httpsTrackingEnabled && // Only show for HTTP tracking\n !outputs.dnsAutoCreated &&\n (!outputs.dnsRecords || outputs.dnsRecords.length === 0) &&\n (!outputs.trackingDomainDnsRecords ||\n outputs.trackingDomainDnsRecords.length === 0)\n ) {\n const trackingLines = [\n pc.bold(\"Tracking Domain (CNAME):\"),\n ` ${pc.cyan(outputs.customTrackingDomain)} ${pc.dim(\"CNAME\")} \"r.${outputs.region}.awstrack.me\"`,\n \"\",\n pc.dim(\n \"Note: This CNAME allows SES to rewrite links in your emails to use\"\n ),\n pc.dim(\"your custom domain for open and click tracking.\"),\n ];\n\n clack.note(trackingLines.join(\"\\n\"), \"DNS Record to add:\");\n }\n}\n\n/**\n * Status output configuration\n */\nexport type StatusOutputs = {\n integrationLevel: \"dashboard-only\" | \"enhanced\";\n region: string;\n domains: Array<{\n domain: string;\n status: \"verified\" | \"pending\" | \"failed\";\n dkimTokens?: string[];\n mailFromDomain?: string;\n mailFromStatus?: string;\n }>;\n resources: {\n roleArn?: string;\n configSetName?: string;\n tableName?: string;\n lambdaFunctions?: number;\n snsTopics?: number;\n archiveArn?: string;\n archivingEnabled?: boolean;\n archiveRetention?: string;\n };\n tracking?: {\n customTrackingDomain?: string;\n httpsEnabled?: boolean;\n cloudFrontDomain?: string;\n };\n};\n\n/**\n * Display status information\n */\nexport function displayStatus(status: StatusOutputs) {\n clack.intro(pc.bold(\"Wraps Email Infrastructure\"));\n\n const infoLines = [\n `${pc.bold(\"Integration:\")} ${pc.cyan(status.integrationLevel)}`,\n `${pc.bold(\"Region:\")} ${pc.cyan(status.region)}`,\n ];\n\n if (status.domains.length > 0) {\n const domainStrings = status.domains.map((d) => {\n const statusIcon =\n d.status === \"verified\" ? \"✓\" : d.status === \"pending\" ? \"⏱\" : \"✗\";\n const statusColor =\n d.status === \"verified\"\n ? pc.green\n : d.status === \"pending\"\n ? pc.yellow\n : pc.red;\n\n let domainLine = ` ${d.domain} ${statusColor(`${statusIcon} ${d.status}`)}`;\n\n // Add MAIL FROM domain info if configured\n if (d.mailFromDomain) {\n const mailFromStatusIcon = d.mailFromStatus === \"SUCCESS\" ? \"✓\" : \"⏱\";\n const mailFromColor =\n d.mailFromStatus === \"SUCCESS\" ? pc.green : pc.yellow;\n domainLine += `\\n ${pc.dim(\"MAIL FROM:\")} ${d.mailFromDomain} ${mailFromColor(mailFromStatusIcon)}`;\n }\n\n return domainLine;\n });\n infoLines.push(`${pc.bold(\"Domains:\")}\\n${domainStrings.join(\"\\n\")}`);\n }\n\n clack.note(infoLines.join(\"\\n\"), \"Configuration\");\n\n // Features\n const featureLines = [];\n featureLines.push(` ${pc.green(\"✓\")} Email Sending ${pc.dim(\"(via SES)\")}`);\n\n if (status.resources.tableName) {\n featureLines.push(\n ` ${pc.green(\"✓\")} Email Tracking ${pc.dim(\"(DynamoDB logs)\")}`\n );\n } else {\n featureLines.push(\n ` ${pc.dim(\"○\")} Email Tracking ${pc.dim(\"(run 'wraps email upgrade' to enable)\")}`\n );\n }\n\n if (\n status.resources.lambdaFunctions &&\n status.resources.lambdaFunctions > 0\n ) {\n featureLines.push(\n ` ${pc.green(\"✓\")} Bounce/Complaint Handling ${pc.dim(\"(automated)\")}`\n );\n } else {\n featureLines.push(\n ` ${pc.dim(\"○\")} Bounce/Complaint Handling ${pc.dim(\"(run 'wraps email upgrade' to enable)\")}`\n );\n }\n\n // Email Archiving\n if (status.resources.archivingEnabled) {\n const retentionLabel =\n {\n \"7days\": \"7 days\",\n \"30days\": \"30 days\",\n \"90days\": \"90 days\",\n \"6months\": \"6 months\",\n \"1year\": \"1 year\",\n \"18months\": \"18 months\",\n }[status.resources.archiveRetention || \"90days\"] || \"90 days\";\n featureLines.push(\n ` ${pc.green(\"✓\")} Email Archiving ${pc.dim(`(${retentionLabel} retention)`)}`\n );\n } else {\n featureLines.push(\n ` ${pc.dim(\"○\")} Email Archiving ${pc.dim(\"(run 'wraps email upgrade' to enable)\")}`\n );\n }\n\n // Custom Tracking Domain\n if (status.tracking?.customTrackingDomain) {\n const protocol = status.tracking.httpsEnabled ? \"HTTPS\" : \"HTTP\";\n const cloudFrontStatus = status.tracking.httpsEnabled\n ? status.tracking.cloudFrontDomain\n ? pc.green(\"✓ Active\")\n : pc.yellow(\"⏱ Pending\")\n : \"\";\n const trackingLabel = status.tracking.httpsEnabled\n ? `${protocol} tracking ${cloudFrontStatus}`\n : `${protocol} tracking`;\n featureLines.push(\n ` ${pc.green(\"✓\")} Custom Tracking Domain ${pc.dim(`(${trackingLabel})`)}`\n );\n featureLines.push(` ${pc.cyan(status.tracking.customTrackingDomain)}`);\n } else {\n featureLines.push(\n ` ${pc.dim(\"○\")} Custom Tracking Domain ${pc.dim(\"(run 'wraps email upgrade' to enable)\")}`\n );\n }\n\n featureLines.push(\n ` ${pc.green(\"✓\")} Console Dashboard ${pc.dim(\"(run 'wraps console')\")}`\n );\n\n clack.note(featureLines.join(\"\\n\"), \"Features\");\n\n // Resources\n const resourceLines = [];\n\n if (status.resources.roleArn) {\n resourceLines.push(\n ` ${pc.green(\"✓\")} IAM Role: ${pc.cyan(status.resources.roleArn)}`\n );\n }\n\n if (status.resources.configSetName) {\n resourceLines.push(\n ` ${pc.green(\"✓\")} Configuration Set: ${pc.cyan(status.resources.configSetName)}`\n );\n }\n\n if (status.resources.tableName) {\n resourceLines.push(\n ` ${pc.green(\"✓\")} DynamoDB Table: ${pc.cyan(status.resources.tableName)}`\n );\n }\n\n if (status.resources.lambdaFunctions) {\n resourceLines.push(\n ` ${pc.green(\"✓\")} Lambda Functions: ${pc.cyan(\n `${status.resources.lambdaFunctions} deployed`\n )}`\n );\n }\n\n if (status.resources.snsTopics) {\n resourceLines.push(\n ` ${pc.green(\"✓\")} SNS Topics: ${pc.cyan(`${status.resources.snsTopics} configured`)}`\n );\n }\n\n if (status.resources.archiveArn) {\n resourceLines.push(\n ` ${pc.green(\"✓\")} Mail Manager Archive: ${pc.cyan(status.resources.archiveArn)}`\n );\n }\n\n clack.note(resourceLines.join(\"\\n\"), \"Resources\");\n\n // Show DNS records for pending domains OR domains with pending MAIL FROM\n const domainsNeedingDNS = status.domains.filter(\n (d) =>\n (d.status === \"pending\" && d.dkimTokens) ||\n (d.mailFromDomain && d.mailFromStatus !== \"SUCCESS\")\n );\n if (domainsNeedingDNS.length > 0) {\n for (const domain of domainsNeedingDNS) {\n const dnsLines = [];\n\n // DKIM records (only for pending domains)\n if (\n domain.status === \"pending\" &&\n domain.dkimTokens &&\n domain.dkimTokens.length > 0\n ) {\n // Use MAIL FROM domain for DMARC rua if configured, otherwise use main domain\n const dmarcRuaDomain = domain.mailFromDomain || domain.domain;\n dnsLines.push(\n pc.bold(\"DKIM Records (CNAME):\"),\n ...domain.dkimTokens.map(\n (token) =>\n ` ${pc.cyan(`${token}._domainkey.${domain.domain}`)} ${pc.dim(\"CNAME\")} \"${token}.dkim.amazonses.com\"`\n ),\n \"\",\n pc.bold(\"SPF Record (TXT):\"),\n ` ${pc.cyan(domain.domain)} ${pc.dim(\"TXT\")} \"v=spf1 include:amazonses.com ~all\"`,\n pc.dim(\n \" Note: If you have an existing SPF record, add 'include:amazonses.com' to it\"\n ),\n \"\",\n pc.bold(\"DMARC Record (TXT):\"),\n ` ${pc.cyan(`_dmarc.${domain.domain}`)} ${pc.dim(\"TXT\")} \"v=DMARC1; p=quarantine; rua=mailto:postmaster@${dmarcRuaDomain}\"`\n );\n }\n\n // MAIL FROM records (if configured but not verified)\n if (domain.mailFromDomain && domain.mailFromStatus !== \"SUCCESS\") {\n if (dnsLines.length > 0) {\n dnsLines.push(\"\");\n }\n dnsLines.push(\n pc.bold(\"MAIL FROM Domain Records (for DMARC alignment):\"),\n ` ${pc.cyan(domain.mailFromDomain)} ${pc.dim(\"MX\")} \"10 feedback-smtp.${status.region}.amazonses.com\"`,\n ` ${pc.cyan(domain.mailFromDomain)} ${pc.dim(\"TXT\")} \"v=spf1 include:amazonses.com ~all\"`\n );\n }\n\n if (dnsLines.length > 0) {\n clack.note(dnsLines.join(\"\\n\"), `DNS Records for ${domain.domain}`);\n }\n }\n\n // Show verify command with first domain needing DNS as example\n const exampleDomain = domainsNeedingDNS[0].domain;\n console.log(\n `\\n${pc.dim(\"Run:\")} ${pc.yellow(`wraps email verify --domain ${exampleDomain}`)} ${pc.dim(\n \"(after DNS propagates)\"\n )}\\n`\n );\n }\n\n console.log(`\\n${pc.bold(\"Dashboard:\")} ${pc.blue(\"https://app.wraps.dev\")}`);\n console.log(`${pc.bold(\"Docs:\")} ${pc.blue(\"https://wraps.dev/docs\")}\\n`);\n}\n\n/**\n * Preview output configuration\n */\nexport type PreviewOutputs = {\n changeSummary: {\n create?: number;\n update?: number;\n delete?: number;\n same?: number;\n replace?: number;\n };\n costEstimate?: string;\n commandName: string;\n};\n\n/**\n * Display preview results with resource changes and cost estimate\n */\nexport function displayPreview(outputs: PreviewOutputs): void {\n console.log(pc.yellow(\"\\n--- PREVIEW MODE (no changes will be made) ---\\n\"));\n\n // Display change summary\n const changes = outputs.changeSummary;\n const summaryLines: string[] = [];\n\n if (changes.create && changes.create > 0) {\n summaryLines.push(` ${pc.green(\"+\")} ${changes.create} to create`);\n }\n if (changes.update && changes.update > 0) {\n summaryLines.push(` ${pc.yellow(\"~\")} ${changes.update} to update`);\n }\n if (changes.delete && changes.delete > 0) {\n summaryLines.push(` ${pc.red(\"-\")} ${changes.delete} to destroy`);\n }\n if (changes.same && changes.same > 0) {\n summaryLines.push(` ${pc.dim(\"=\")} ${changes.same} unchanged`);\n }\n if (changes.replace && changes.replace > 0) {\n summaryLines.push(` ${pc.magenta(\"+-\")} ${changes.replace} to replace`);\n }\n\n if (summaryLines.length > 0) {\n clack.note(summaryLines.join(\"\\n\"), \"Resource Changes\");\n } else {\n clack.note(\"No changes detected\", \"Resource Changes\");\n }\n\n // Display cost estimate\n if (outputs.costEstimate) {\n clack.note(outputs.costEstimate, \"Estimated Monthly Cost\");\n }\n\n console.log(pc.yellow(\"\\n--- END PREVIEW (no changes were made) ---\\n\"));\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { deployEmailStack } from \"../../infrastructure/email-stack.js\";\nimport { trackCommand, trackError } from \"../../telemetry/events.js\";\nimport type {\n EmailConfigOptions,\n EmailStackConfig,\n} from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { errors } from \"../../utils/shared/errors.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n loadConnectionMetadata,\n saveConnectionMetadata,\n} from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayPreview,\n displaySuccess,\n} from \"../../utils/shared/output.js\";\nimport { ensurePulumiInstalled } from \"../../utils/shared/pulumi.js\";\n\n/**\n * Config command - Redeploy infrastructure to apply CLI updates\n * This command updates Lambda functions and other managed resources\n * without requiring configuration changes from the user.\n */\nexport async function config(options: EmailConfigOptions): Promise<void> {\n const startTime = Date.now();\n\n clack.intro(\n pc.bold(\n options.preview\n ? \"Wraps Config Preview\"\n : \"Wraps Config - Apply CLI Updates to Infrastructure\"\n )\n );\n\n const progress = new DeploymentProgress();\n\n // 1. Check Pulumi CLI is installed\n const wasAutoInstalled = await progress.execute(\n \"Checking Pulumi CLI installation\",\n async () => await ensurePulumiInstalled()\n );\n\n if (wasAutoInstalled) {\n progress.info(\"Pulumi CLI was automatically installed\");\n }\n\n // 2. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`Connected to AWS account: ${pc.cyan(identity.accountId)}`);\n\n // 3. Get region\n let region = options.region;\n if (!region) {\n const defaultRegion = await getAWSRegion();\n region = defaultRegion;\n }\n\n // 4. Load existing connection metadata\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n\n if (!metadata) {\n clack.log.error(\n `No Wraps connection found for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} to create new infrastructure or ${pc.cyan(\"wraps email connect\")} to connect existing.`\n );\n process.exit(1);\n }\n\n progress.info(`Found existing connection created: ${metadata.timestamp}`);\n\n // 5. Display current configuration\n console.log(`\\n${pc.bold(\"Current Configuration:\")}\\n`);\n\n if (metadata.services.email?.preset) {\n console.log(` Preset: ${pc.cyan(metadata.services.email?.preset)}`);\n } else {\n console.log(` Preset: ${pc.cyan(\"custom\")}`);\n }\n\n const config = metadata.services.email?.config;\n\n if (!config) {\n clack.log.error(\"No email configuration found in metadata\");\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} to create new infrastructure.`\n );\n process.exit(1);\n }\n\n // Show sending domain if configured\n if (config.domain) {\n console.log(` Sending Domain: ${pc.cyan(config.domain)}`);\n }\n\n if (config.tracking?.enabled) {\n console.log(` ${pc.green(\"✓\")} Open & Click Tracking`);\n }\n\n if (config.suppressionList?.enabled) {\n console.log(` ${pc.green(\"✓\")} Bounce/Complaint Suppression`);\n }\n\n if (config.eventTracking?.enabled) {\n console.log(` ${pc.green(\"✓\")} Event Tracking (EventBridge)`);\n }\n\n if (config.dedicatedIp) {\n console.log(` ${pc.green(\"✓\")} Dedicated IP Address`);\n }\n\n console.log(\"\");\n\n // 6. Show what will be updated\n console.log(`${pc.bold(\"What will be updated:\")}\\n`);\n console.log(\n ` ${pc.cyan(\"•\")} Lambda function code (if event tracking enabled)`\n );\n console.log(\n ` ${pc.cyan(\"•\")} EventBridge rules (if event tracking enabled)`\n );\n console.log(` ${pc.cyan(\"•\")} IAM policies (security improvements)`);\n console.log(` ${pc.cyan(\"•\")} SES configuration set (feature updates)`);\n console.log(\"\");\n\n progress.info(\n \"Your current configuration will be preserved - no features will be added or removed\"\n );\n console.log(\"\");\n\n // 7. Confirm update (skip if --yes or --preview)\n if (!(options.yes || options.preview)) {\n const confirmed = await clack.confirm({\n message: \"Proceed with update?\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel(\"Update cancelled.\");\n process.exit(0);\n }\n }\n\n // 8. Get Vercel config if needed\n let vercelConfig;\n if (metadata.provider === \"vercel\" && metadata.vercel) {\n vercelConfig = metadata.vercel;\n }\n\n // 9. Build stack configuration (reuse existing config)\n const stackConfig: EmailStackConfig = {\n provider: metadata.provider,\n region,\n vercel: vercelConfig,\n emailConfig: config,\n };\n\n // 10. Preview or Update Pulumi stack\n if (options.preview) {\n // PREVIEW MODE - show what would be updated without deploying\n try {\n const previewResult = await progress.execute(\n \"Generating update preview\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName:\n metadata.services.email?.pulumiStackName ||\n `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Refresh state to sync with AWS before previewing\n await stack.refresh({ onOutput: () => {} });\n\n // Run preview instead of deployment\n const result = await stack.preview({ diff: true });\n return result;\n }\n );\n\n // Display preview results\n displayPreview({\n changeSummary: previewResult.changeSummary,\n commandName: \"wraps email config\",\n });\n\n clack.outro(\n pc.green(\"Preview complete. Run without --preview to update.\")\n );\n\n // Track preview completion\n trackCommand(\"email:config\", {\n success: true,\n preview: true,\n duration_ms: Date.now() - startTime,\n });\n return;\n } catch (error: any) {\n trackError(\"PREVIEW_FAILED\", \"email:config\", { step: \"preview\" });\n if (error.message?.includes(\"stack is currently locked\")) {\n throw errors.stackLocked();\n }\n throw new Error(`Preview failed: ${error.message}`);\n }\n }\n\n // UPDATE MODE - actually update infrastructure\n let outputs;\n try {\n outputs = await progress.execute(\n \"Updating Wraps infrastructure (this may take 2-3 minutes)\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName:\n metadata.services.email?.pulumiStackName ||\n `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.workspace.selectStack(\n metadata.services.email?.pulumiStackName ||\n `wraps-${identity.accountId}-${region}`\n );\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Refresh state to sync with actual AWS resources (prevents AlreadyExists errors)\n await stack.refresh({ onOutput: () => {} });\n\n // Pulumi will automatically detect changes and only update what's needed\n const upResult = await stack.up({ onOutput: () => {} });\n const pulumiOutputs = upResult.outputs;\n\n return {\n roleArn: pulumiOutputs.roleArn?.value as string,\n configSetName: pulumiOutputs.configSetName?.value as\n | string\n | undefined,\n tableName: pulumiOutputs.tableName?.value as string | undefined,\n region: pulumiOutputs.region?.value as string,\n lambdaFunctions: pulumiOutputs.lambdaFunctions?.value as\n | string[]\n | undefined,\n domain: pulumiOutputs.domain?.value as string | undefined,\n dkimTokens: pulumiOutputs.dkimTokens?.value as string[] | undefined,\n customTrackingDomain: pulumiOutputs.customTrackingDomain?.value as\n | string\n | undefined,\n };\n }\n );\n } catch (error: any) {\n // Track update failure\n trackCommand(\"email:config\", {\n success: false,\n duration_ms: Date.now() - startTime,\n });\n\n // Check if it's a lock file error\n if (error.message?.includes(\"stack is currently locked\")) {\n trackError(\"STACK_LOCKED\", \"email:config\", { step: \"update\" });\n throw errors.stackLocked();\n }\n\n trackError(\"UPDATE_FAILED\", \"email:config\", { step: \"update\" });\n throw new Error(`Pulumi update failed: ${error.message}`);\n }\n\n // 11. Update metadata timestamp (config stays the same)\n metadata.timestamp = new Date().toISOString();\n await saveConnectionMetadata(metadata);\n\n progress.info(\"Connection metadata updated\");\n\n // 12. Display success message\n displaySuccess({\n roleArn: outputs.roleArn,\n configSetName: outputs.configSetName,\n region: outputs.region!,\n tableName: outputs.tableName,\n customTrackingDomain: outputs.customTrackingDomain,\n });\n\n // Show what was updated\n console.log(`\\n${pc.green(\"✓\")} ${pc.bold(\"Update complete!\")}\\n`);\n console.log(\n \"Infrastructure has been updated with the latest CLI improvements.\\n\"\n );\n console.log(`${pc.bold(\"Next steps:\")}\\n`);\n console.log(\n ` ${pc.cyan(\"1.\")} No code changes needed - your existing SDK integration continues to work`\n );\n console.log(\n ` ${pc.cyan(\"2.\")} Check ${pc.cyan(\"wraps status\")} to verify all resources are healthy`\n );\n console.log(\n ` ${pc.cyan(\"3.\")} View analytics at ${pc.cyan(\"wraps console\")}\\n`\n );\n\n // 13. Track successful update\n trackCommand(\"email:config\", {\n success: true,\n duration_ms: Date.now() - startTime,\n });\n}\n","import * as aws from \"@pulumi/aws\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport type { EmailStackConfig, StackOutputs } from \"../types/index.js\";\nimport { createDynamoDBTables } from \"./resources/dynamodb.js\";\nimport { createEventBridgeResources } from \"./resources/eventbridge.js\";\nimport { createIAMRole } from \"./resources/iam.js\";\nimport { deployLambdaFunctions } from \"./resources/lambda.js\";\nimport { createSESResources, eventDestinationExists } from \"./resources/ses.js\";\nimport { createSQSResources } from \"./resources/sqs.js\";\nimport { createVercelOIDC } from \"./vercel-oidc.js\";\n\n/**\n * Deploy email infrastructure stack using Pulumi\n */\nexport async function deployEmailStack(\n config: EmailStackConfig\n): Promise<StackOutputs> {\n // Get current AWS account\n const identity = await aws.getCallerIdentity();\n const accountId = identity.accountId;\n\n let oidcProvider: aws.iam.OpenIdConnectProvider | undefined;\n\n // 1. Create OIDC provider if Vercel\n if (config.provider === \"vercel\" && config.vercel) {\n oidcProvider = await createVercelOIDC({\n teamSlug: config.vercel.teamSlug,\n accountId,\n });\n }\n\n const emailConfig = config.emailConfig;\n\n // 2. Create IAM role\n const role = await createIAMRole({\n provider: config.provider,\n oidcProvider,\n vercelTeamSlug: config.vercel?.teamSlug,\n vercelProjectName: config.vercel?.projectName,\n emailConfig,\n });\n\n // 3. CloudFront + ACM (if HTTPS tracking enabled)\n let cloudFrontResources;\n let acmResources;\n\n if (\n emailConfig.tracking?.enabled &&\n emailConfig.tracking.customRedirectDomain &&\n emailConfig.tracking.httpsEnabled\n ) {\n // Check for Route53 hosted zone (for automatic DNS validation)\n const { findHostedZone } = await import(\"../utils/route53.js\");\n const hostedZone = await findHostedZone(\n emailConfig.tracking.customRedirectDomain,\n config.region\n );\n\n // Create ACM certificate (in us-east-1 for CloudFront)\n const { createACMCertificate } = await import(\"./resources/acm.js\");\n acmResources = await createACMCertificate({\n domain: emailConfig.tracking.customRedirectDomain,\n hostedZoneId: hostedZone?.id,\n });\n\n // Create CloudFront distribution with SSL certificate\n // Import CloudFront creation function\n const { createCloudFrontTracking } = await import(\n \"./resources/cloudfront.js\"\n );\n\n // Determine which certificate ARN to use:\n // - Route53: Use certificateValidation.certificateArn (waits for validation)\n // - Manual DNS: Use certificate.arn directly (CloudFront will fail if not validated)\n const certificateArn = acmResources.certificateValidation\n ? acmResources.certificateValidation.certificateArn\n : acmResources.certificate.arn;\n\n cloudFrontResources = await createCloudFrontTracking({\n customTrackingDomain: emailConfig.tracking.customRedirectDomain,\n region: config.region,\n certificateArn,\n hostedZoneId: hostedZone?.id, // Pass hosted zone ID for automatic DNS record creation\n });\n }\n\n // 4. SES resources (if tracking or event tracking enabled)\n let sesResources;\n if (emailConfig.tracking?.enabled || emailConfig.eventTracking?.enabled) {\n // Check if the event destination already exists in AWS but not in Pulumi state\n // This can happen if resources were created outside Pulumi or state got out of sync\n const shouldImportEventDest =\n emailConfig.eventTracking?.enabled &&\n (await eventDestinationExists(\n \"wraps-email-tracking\",\n \"wraps-email-eventbridge\",\n config.region\n ));\n\n // Compute mailFromDomain from mailFromSubdomain if provided\n let mailFromDomain = emailConfig.mailFromDomain;\n if (\n !mailFromDomain &&\n emailConfig.mailFromSubdomain &&\n emailConfig.domain\n ) {\n mailFromDomain = `${emailConfig.mailFromSubdomain}.${emailConfig.domain}`;\n }\n\n sesResources = await createSESResources({\n domain: emailConfig.domain,\n mailFromDomain,\n region: config.region,\n trackingConfig: emailConfig.tracking,\n eventTypes: emailConfig.eventTracking?.events,\n eventTrackingEnabled: emailConfig.eventTracking?.enabled, // Pass flag to create EventBridge destination\n tlsRequired: emailConfig.tlsRequired, // Require TLS encryption for all emails\n importExistingEventDestination: shouldImportEventDest, // Import if exists to avoid AlreadyExistsException\n });\n }\n\n // 5. DynamoDB tables (if history storage enabled)\n let dynamoTables;\n if (emailConfig.eventTracking?.dynamoDBHistory) {\n dynamoTables = await createDynamoDBTables({\n retention: emailConfig.eventTracking.archiveRetention,\n });\n }\n\n // 6. SQS queues (if event tracking enabled)\n let sqsResources;\n if (emailConfig.eventTracking?.enabled) {\n sqsResources = await createSQSResources();\n }\n\n // 7. EventBridge rule to route SES events to SQS (if event tracking enabled)\n if (emailConfig.eventTracking?.enabled && sesResources && sqsResources) {\n await createEventBridgeResources({\n eventBusArn: sesResources.eventBus.arn,\n queueArn: sqsResources.queue.arn,\n queueUrl: sqsResources.queue.url,\n });\n }\n\n // 8. Lambda functions (if event tracking and DynamoDB enabled)\n let lambdaFunctions;\n if (\n emailConfig.eventTracking?.dynamoDBHistory &&\n dynamoTables &&\n sqsResources\n ) {\n lambdaFunctions = await deployLambdaFunctions({\n roleArn: role.arn,\n tableName: dynamoTables.emailHistory.name,\n queueArn: sqsResources.queue.arn,\n accountId,\n region: config.region,\n });\n }\n\n // 9. Mail Manager Archive (if email archiving enabled)\n let archiveResources;\n if (emailConfig.emailArchiving?.enabled && sesResources) {\n const { createMailManagerArchive } = await import(\n \"./resources/mail-manager.js\"\n );\n archiveResources = await createMailManagerArchive({\n name: \"email\",\n retention: emailConfig.emailArchiving.retention,\n configSetName: sesResources.configSet.configurationSetName,\n region: config.region,\n });\n }\n\n // Return outputs\n return {\n roleArn: role.arn as any as string,\n configSetName: sesResources?.configSet.configurationSetName as any as\n | string\n | undefined,\n tableName: dynamoTables?.emailHistory.name as any as string | undefined,\n region: config.region,\n lambdaFunctions: lambdaFunctions\n ? [lambdaFunctions.eventProcessor.arn as any as string]\n : undefined,\n domain: emailConfig.domain,\n dkimTokens: sesResources?.dkimTokens as any as string[] | undefined,\n dnsAutoCreated: sesResources?.dnsAutoCreated,\n eventBusName: sesResources?.eventBus.name as any as string | undefined,\n queueUrl: sqsResources?.queue.url as any as string | undefined,\n dlqUrl: sqsResources?.dlq.url as any as string | undefined,\n customTrackingDomain: sesResources?.customTrackingDomain,\n httpsTrackingEnabled: emailConfig.tracking?.httpsEnabled,\n cloudFrontDomain: cloudFrontResources?.domainName as any as\n | string\n | undefined,\n acmCertificateValidationRecords: acmResources?.validationRecords as any as\n | Array<{ name: string; type: string; value: string }>\n | undefined,\n mailFromDomain: sesResources?.mailFromDomain,\n archiveArn: archiveResources?.archiveArn,\n archivingEnabled: emailConfig.emailArchiving?.enabled,\n archiveRetention: emailConfig.emailArchiving?.enabled\n ? emailConfig.emailArchiving.retention\n : undefined,\n };\n}\n\n/**\n * Run Pulumi program inline\n */\nexport async function runPulumiProgram(\n stackName: string,\n program: () => Promise<StackOutputs>\n): Promise<StackOutputs> {\n const stack = await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName,\n projectName: \"wraps-email\",\n program,\n },\n {\n workDir: `${process.env.HOME}/.wraps/pulumi`,\n }\n );\n\n // Set AWS region\n await stack.setConfig(\"aws:region\", { value: \"us-east-1\" });\n\n // Run the deployment\n const upResult = await stack.up({\n onOutput: (msg) => process.stdout.write(msg),\n });\n\n // Get outputs\n const outputs = upResult.outputs;\n\n return {\n roleArn: outputs.roleArn?.value as string,\n configSetName: outputs.configSetName?.value as string | undefined,\n tableName: outputs.tableName?.value as string | undefined,\n region: outputs.region?.value as string,\n };\n}\n","import * as aws from \"@pulumi/aws\";\nimport type { ArchiveRetention } from \"../../types/index.js\";\n\n/**\n * DynamoDB configuration\n */\nexport type DynamoDBConfig = {\n retention?: ArchiveRetention;\n};\n\n/**\n * DynamoDB tables output\n */\nexport type DynamoDBTables = {\n emailHistory: aws.dynamodb.Table;\n};\n\n/**\n * Check if DynamoDB table exists\n */\nasync function tableExists(tableName: string): Promise<boolean> {\n try {\n const { DynamoDBClient, DescribeTableCommand } = await import(\n \"@aws-sdk/client-dynamodb\"\n );\n const dynamodb = new DynamoDBClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n\n await dynamodb.send(new DescribeTableCommand({ TableName: tableName }));\n return true;\n } catch (error: any) {\n if (error.name === \"ResourceNotFoundException\") {\n return false;\n }\n console.error(\"Error checking for existing DynamoDB table:\", error);\n return false;\n }\n}\n\n/**\n * Create DynamoDB tables for email tracking\n */\nexport async function createDynamoDBTables(\n _config?: DynamoDBConfig\n): Promise<DynamoDBTables> {\n // Check if table already exists\n const tableName = \"wraps-email-history\";\n const exists = await tableExists(tableName);\n\n // Email history table (TTL is set based on retention in Lambda via expiresAt field)\n // Note: retention config is passed but TTL is actually managed by Lambda setting expiresAt\n const emailHistory = exists\n ? new aws.dynamodb.Table(\n tableName,\n {\n name: tableName,\n billingMode: \"PAY_PER_REQUEST\",\n hashKey: \"messageId\",\n rangeKey: \"sentAt\",\n attributes: [\n { name: \"messageId\", type: \"S\" },\n { name: \"sentAt\", type: \"N\" },\n { name: \"accountId\", type: \"S\" },\n ],\n globalSecondaryIndexes: [\n {\n name: \"accountId-sentAt-index\",\n hashKey: \"accountId\",\n rangeKey: \"sentAt\",\n projectionType: \"ALL\",\n },\n ],\n ttl: {\n enabled: true,\n attributeName: \"expiresAt\",\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n },\n },\n {\n import: tableName, // Import existing table\n }\n )\n : new aws.dynamodb.Table(tableName, {\n name: tableName,\n billingMode: \"PAY_PER_REQUEST\",\n hashKey: \"messageId\",\n rangeKey: \"sentAt\",\n attributes: [\n { name: \"messageId\", type: \"S\" },\n { name: \"sentAt\", type: \"N\" },\n { name: \"accountId\", type: \"S\" },\n ],\n globalSecondaryIndexes: [\n {\n name: \"accountId-sentAt-index\",\n hashKey: \"accountId\",\n rangeKey: \"sentAt\",\n projectionType: \"ALL\",\n },\n ],\n ttl: {\n enabled: true,\n attributeName: \"expiresAt\",\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n },\n });\n\n return {\n emailHistory,\n };\n}\n","import * as aws from \"@pulumi/aws\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\n/**\n * EventBridge resources configuration\n */\nexport type EventBridgeConfig = {\n eventBusArn: pulumi.Output<string>;\n queueArn: pulumi.Output<string>;\n queueUrl: pulumi.Output<string>;\n};\n\n/**\n * EventBridge resources output\n */\nexport type EventBridgeResources = {\n rule: aws.cloudwatch.EventRule;\n target: aws.cloudwatch.EventTarget;\n};\n\n/**\n * Create EventBridge rule to route SES events to SQS queue\n *\n * This rule captures all SES events from the default event bus\n * and routes them to the SQS queue for processing.\n *\n * Note: SES can only send to the default EventBridge bus, not custom buses.\n */\nexport async function createEventBridgeResources(\n config: EventBridgeConfig\n): Promise<EventBridgeResources> {\n // Extract event bus name from ARN (will be \"default\" for SES)\n const eventBusName = config.eventBusArn.apply((arn) => arn.split(\"/\").pop()!);\n\n // EventBridge rule to capture all SES events on default bus\n const rule = new aws.cloudwatch.EventRule(\"wraps-email-events-rule\", {\n name: \"wraps-email-events-to-sqs\",\n description: \"Route all SES email events to SQS for processing\",\n eventBusName,\n eventPattern: JSON.stringify({\n source: [\"aws.ses\"],\n // SES sends events with various detail-types based on event type\n // We capture all by not filtering on detail-type\n }),\n tags: {\n ManagedBy: \"wraps-cli\",\n },\n });\n\n // SQS queue policy to allow EventBridge to send messages\n new aws.sqs.QueuePolicy(\"wraps-email-events-queue-policy\", {\n queueUrl: config.queueUrl,\n policy: pulumi\n .all([config.queueArn, rule.arn])\n .apply(([queueArn, ruleArn]) =>\n JSON.stringify({\n Version: \"2012-10-17\",\n Statement: [\n {\n Effect: \"Allow\",\n Principal: {\n Service: \"events.amazonaws.com\",\n },\n Action: \"sqs:SendMessage\",\n Resource: queueArn,\n Condition: {\n ArnEquals: {\n \"aws:SourceArn\": ruleArn,\n },\n },\n },\n ],\n })\n ),\n });\n\n // EventBridge target to send events to SQS\n const target = new aws.cloudwatch.EventTarget(\"wraps-email-events-target\", {\n rule: rule.name,\n eventBusName,\n arn: config.queueArn,\n });\n\n return {\n rule,\n target,\n };\n}\n","import * as aws from \"@pulumi/aws\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport type { Provider, WrapsEmailConfig } from \"../../types/index.js\";\n\n/**\n * IAM role configuration\n */\nexport type IAMRoleConfig = {\n provider: Provider;\n oidcProvider?: aws.iam.OpenIdConnectProvider;\n vercelTeamSlug?: string;\n vercelProjectName?: string;\n emailConfig: WrapsEmailConfig;\n};\n\n/**\n * Check if IAM role exists\n */\nasync function roleExists(roleName: string): Promise<boolean> {\n try {\n const { IAMClient, GetRoleCommand } = await import(\"@aws-sdk/client-iam\");\n // IAM is global but SDK still requires a region\n const iam = new IAMClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n\n await iam.send(new GetRoleCommand({ RoleName: roleName }));\n return true;\n } catch (error: any) {\n if (error.name === \"NoSuchEntityException\") {\n return false;\n }\n console.error(\"Error checking for existing IAM role:\", error);\n return false;\n }\n}\n\n/**\n * Create IAM role for email infrastructure\n */\nexport async function createIAMRole(\n config: IAMRoleConfig\n): Promise<aws.iam.Role> {\n // Build assume role policy based on provider\n let assumeRolePolicy: pulumi.Output<string>;\n\n if (config.provider === \"vercel\" && config.oidcProvider) {\n assumeRolePolicy = pulumi.interpolate`{\n \"Version\": \"2012-10-17\",\n \"Statement\": [{\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Federated\": \"${config.oidcProvider.arn}\"\n },\n \"Action\": \"sts:AssumeRoleWithWebIdentity\",\n \"Condition\": {\n \"StringEquals\": {\n \"oidc.vercel.com/${config.vercelTeamSlug}:aud\": \"https://vercel.com/${config.vercelTeamSlug}\"\n },\n \"StringLike\": {\n \"oidc.vercel.com/${config.vercelTeamSlug}:sub\": \"owner:${config.vercelTeamSlug}:project:${config.vercelProjectName}:environment:*\"\n }\n }\n }]\n }`;\n } else if (config.provider === \"aws\") {\n // Native AWS - EC2, Lambda, ECS can assume\n assumeRolePolicy = pulumi.output(`{\n \"Version\": \"2012-10-17\",\n \"Statement\": [{\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Service\": [\"lambda.amazonaws.com\", \"ec2.amazonaws.com\", \"ecs-tasks.amazonaws.com\"]\n },\n \"Action\": \"sts:AssumeRole\"\n }]\n }`);\n } else {\n // Other providers - will use access keys\n throw new Error(\"Other providers not yet implemented\");\n }\n\n // Check if role already exists\n const roleName = \"wraps-email-role\";\n const exists = await roleExists(roleName);\n\n const role = exists\n ? new aws.iam.Role(\n roleName,\n {\n name: roleName,\n assumeRolePolicy,\n tags: {\n ManagedBy: \"wraps-cli\",\n Provider: config.provider,\n },\n },\n {\n import: roleName, // Import existing role (use role name, not ARN)\n }\n )\n : new aws.iam.Role(roleName, {\n name: roleName,\n assumeRolePolicy,\n tags: {\n ManagedBy: \"wraps-cli\",\n Provider: config.provider,\n },\n });\n\n // Build policy statements based on enabled features\n const statements: any[] = [];\n\n // Always allow reading SES metrics for dashboard\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"ses:GetSendStatistics\",\n \"ses:ListIdentities\",\n \"ses:GetIdentityVerificationAttributes\",\n \"cloudwatch:GetMetricData\",\n \"cloudwatch:GetMetricStatistics\",\n ],\n Resource: \"*\",\n });\n\n // Allow sending if enabled\n if (config.emailConfig.sendingEnabled !== false) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"ses:SendEmail\",\n \"ses:SendRawEmail\",\n \"ses:SendTemplatedEmail\",\n \"ses:SendBulkTemplatedEmail\",\n ],\n Resource: \"*\",\n });\n }\n\n // Allow DynamoDB access if history storage enabled\n if (config.emailConfig.eventTracking?.dynamoDBHistory) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"dynamodb:PutItem\",\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n \"dynamodb:Scan\",\n \"dynamodb:BatchGetItem\",\n \"dynamodb:DescribeTable\",\n ],\n Resource: [\n \"arn:aws:dynamodb:*:*:table/wraps-email-*\",\n \"arn:aws:dynamodb:*:*:table/wraps-email-*/index/*\",\n ],\n });\n }\n\n // Allow EventBridge access if event tracking enabled\n if (config.emailConfig.eventTracking?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\"events:PutEvents\", \"events:DescribeEventBus\"],\n Resource: \"arn:aws:events:*:*:event-bus/wraps-email-*\",\n });\n }\n\n // Allow SQS access if event tracking enabled\n if (config.emailConfig.eventTracking?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"sqs:SendMessage\",\n \"sqs:ReceiveMessage\",\n \"sqs:DeleteMessage\",\n \"sqs:GetQueueAttributes\",\n ],\n Resource: \"arn:aws:sqs:*:*:wraps-email-*\",\n });\n }\n\n // Allow Mail Manager Archive access if email archiving enabled\n if (config.emailConfig.emailArchiving?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n // Archive search operations\n \"ses:StartArchiveSearch\",\n \"ses:GetArchiveSearchResults\",\n // Archive message retrieval\n \"ses:GetArchiveMessage\",\n \"ses:GetArchiveMessageContent\",\n // Archive metadata\n \"ses:GetArchive\",\n \"ses:ListArchives\",\n // Archive export (for future use)\n \"ses:StartArchiveExport\",\n \"ses:GetArchiveExport\",\n ],\n Resource: \"arn:aws:ses:*:*:mailmanager-archive/*\",\n });\n }\n\n // Attach policy to role\n new aws.iam.RolePolicy(\"wraps-email-policy\", {\n role: role.name,\n policy: JSON.stringify({\n Version: \"2012-10-17\",\n Statement: statements,\n }),\n });\n\n return role;\n}\n","import * as aws from \"@pulumi/aws\";\nimport type { SESEventType } from \"../../types/index.js\";\n\n/**\n * SES resources configuration\n */\nexport type SESResourcesConfig = {\n domain?: string;\n mailFromDomain?: string;\n region: string;\n trackingConfig?: {\n enabled: boolean;\n opens?: boolean;\n clicks?: boolean;\n customRedirectDomain?: string;\n httpsEnabled?: boolean;\n };\n eventTypes?: SESEventType[];\n eventTrackingEnabled?: boolean; // NEW: Whether to create EventBridge event destination\n tlsRequired?: boolean; // Require TLS encryption for all emails\n importExistingEventDestination?: boolean; // Import existing event destination if it exists\n};\n\n/**\n * Check if SES configuration set exists\n */\nasync function configurationSetExists(\n configSetName: string,\n region: string\n): Promise<boolean> {\n try {\n const { SESv2Client, GetConfigurationSetCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n const ses = new SESv2Client({ region });\n\n await ses.send(\n new GetConfigurationSetCommand({ ConfigurationSetName: configSetName })\n );\n return true;\n } catch (error: any) {\n if (error.name === \"NotFoundException\") {\n return false;\n }\n console.error(\"Error checking for existing configuration set:\", error);\n return false;\n }\n}\n\n/**\n * Check if event destination exists for a configuration set\n */\nexport async function eventDestinationExists(\n configSetName: string,\n eventDestName: string,\n region: string\n): Promise<boolean> {\n try {\n const { SESv2Client, GetConfigurationSetEventDestinationsCommand } =\n await import(\"@aws-sdk/client-sesv2\");\n const ses = new SESv2Client({ region });\n\n const response = await ses.send(\n new GetConfigurationSetEventDestinationsCommand({\n ConfigurationSetName: configSetName,\n })\n );\n\n return (\n response.EventDestinations?.some((dest) => dest.Name === eventDestName) ??\n false\n );\n } catch (error: any) {\n if (error.name === \"NotFoundException\") {\n return false;\n }\n // Silently return false on other errors - we'll try to create and handle errors there\n return false;\n }\n}\n\n/**\n * Check if email identity exists\n */\nasync function emailIdentityExists(\n emailIdentity: string,\n region: string\n): Promise<boolean> {\n try {\n const { SESv2Client, GetEmailIdentityCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n const ses = new SESv2Client({ region });\n\n await ses.send(\n new GetEmailIdentityCommand({ EmailIdentity: emailIdentity })\n );\n return true;\n } catch (error: any) {\n if (error.name === \"NotFoundException\") {\n return false;\n }\n console.error(\"Error checking for existing email identity:\", error);\n return false;\n }\n}\n\n/**\n * SES resources output\n */\nexport type SESResources = {\n configSet: aws.sesv2.ConfigurationSet;\n eventBus: aws.cloudwatch.EventBus;\n domainIdentity?: aws.sesv2.EmailIdentity;\n dkimTokens?: string[];\n dnsAutoCreated?: boolean;\n customTrackingDomain?: string;\n mailFromDomain?: string;\n};\n\n/**\n * Create SES resources (configuration set, EventBridge event bus, domain identity)\n */\nexport async function createSESResources(\n config: SESResourcesConfig\n): Promise<SESResources> {\n // Configuration set for tracking (using SESv2 which supports tags)\n const configSetOptions: aws.sesv2.ConfigurationSetArgs = {\n configurationSetName: \"wraps-email-tracking\",\n deliveryOptions: config.tlsRequired\n ? {\n tlsPolicy: \"REQUIRE\", // Require TLS 1.2+ for all emails\n }\n : undefined,\n suppressionOptions: {\n // Automatically suppress hard bounces and complaints at the configuration set level\n // This provides protection even if account-level suppression isn't configured\n suppressedReasons: [\"BOUNCE\", \"COMPLAINT\"],\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n Description: \"Wraps email tracking configuration set\",\n },\n };\n\n // Add custom tracking domain if provided\n // Note: The tracking domain only needs a CNAME DNS record\n // - Without HTTPS: CNAME points to r.{region}.awstrack.me\n // - With HTTPS: CNAME points to CloudFront distribution domain\n if (config.trackingConfig?.customRedirectDomain) {\n configSetOptions.trackingOptions = {\n customRedirectDomain: config.trackingConfig.customRedirectDomain,\n // HTTPS policy depends on whether HTTPS tracking is enabled\n // - REQUIRE: When using CloudFront with SSL certificate\n // - OPTIONAL: When using direct SES tracking endpoint (no SSL)\n httpsPolicy: config.trackingConfig.httpsEnabled ? \"REQUIRE\" : \"OPTIONAL\",\n };\n }\n\n // Check if configuration set already exists\n const configSetName = \"wraps-email-tracking\";\n const exists = await configurationSetExists(configSetName, config.region);\n\n const configSet = exists\n ? new aws.sesv2.ConfigurationSet(configSetName, configSetOptions, {\n import: configSetName, // Import existing configuration set\n })\n : new aws.sesv2.ConfigurationSet(configSetName, configSetOptions);\n\n // SES can only send to the default EventBridge bus\n // We'll use EventBridge rules to route from default bus to SQS\n // Get the default event bus (it always exists)\n const defaultEventBus = aws.cloudwatch.getEventBusOutput({\n name: \"default\",\n });\n\n // Event destination for all SES events -> EventBridge (default bus)\n // Only create if event tracking is enabled\n if (config.eventTrackingEnabled) {\n const eventDestName = \"wraps-email-eventbridge\";\n\n new aws.sesv2.ConfigurationSetEventDestination(\n \"wraps-email-all-events\",\n {\n configurationSetName: configSet.configurationSetName,\n eventDestinationName: eventDestName,\n eventDestination: {\n enabled: true,\n matchingEventTypes: [\n \"SEND\",\n \"DELIVERY\",\n \"OPEN\",\n \"CLICK\",\n \"BOUNCE\",\n \"COMPLAINT\",\n \"REJECT\",\n \"RENDERING_FAILURE\",\n \"DELIVERY_DELAY\",\n \"SUBSCRIPTION\",\n ],\n eventBridgeDestination: {\n // SES requires default bus - cannot use custom bus\n eventBusArn: defaultEventBus.arn,\n },\n },\n },\n {\n // Import existing resource if it already exists in AWS\n // This prevents AlreadyExistsException when the resource exists but isn't in Pulumi state\n import: config.importExistingEventDestination\n ? `wraps-email-tracking|${eventDestName}`\n : undefined,\n }\n );\n }\n\n // Optional: Verify domain if provided\n let domainIdentity: aws.sesv2.EmailIdentity | undefined;\n let dkimTokens: string[] | undefined;\n let mailFromDomain: string | undefined;\n\n if (config.domain) {\n // Check if email identity already exists\n const identityExists = await emailIdentityExists(\n config.domain,\n config.region\n );\n\n // Use SES v2 API to create email identity with configuration set\n domainIdentity = identityExists\n ? new aws.sesv2.EmailIdentity(\n \"wraps-email-domain\",\n {\n emailIdentity: config.domain,\n configurationSetName: configSet.configurationSetName, // Link configuration set to domain\n dkimSigningAttributes: {\n nextSigningKeyLength: \"RSA_2048_BIT\",\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n },\n },\n {\n import: config.domain, // Import existing identity\n }\n )\n : new aws.sesv2.EmailIdentity(\"wraps-email-domain\", {\n emailIdentity: config.domain,\n configurationSetName: configSet.configurationSetName, // Link configuration set to domain\n dkimSigningAttributes: {\n nextSigningKeyLength: \"RSA_2048_BIT\",\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n },\n });\n\n // Extract DKIM tokens for DNS configuration\n dkimTokens = domainIdentity.dkimSigningAttributes.apply(\n (attrs) => attrs?.tokens || []\n ) as any;\n\n // Configure MAIL FROM domain for better DMARC alignment (only if explicitly configured)\n if (config.mailFromDomain) {\n mailFromDomain = config.mailFromDomain;\n\n // Create/update MAIL FROM attributes\n // Note: This resource doesn't support import, but it will update existing config\n new aws.sesv2.EmailIdentityMailFromAttributes(\n \"wraps-email-mail-from\",\n {\n emailIdentity: config.domain,\n mailFromDomain,\n behaviorOnMxFailure: \"USE_DEFAULT_VALUE\", // Fallback to amazonses.com if MX record fails\n },\n {\n dependsOn: [domainIdentity], // Ensure domain identity exists first\n }\n );\n }\n }\n\n return {\n configSet,\n eventBus: defaultEventBus as any, // Return default bus reference\n domainIdentity,\n dkimTokens,\n dnsAutoCreated: false, // Will be set after deployment\n customTrackingDomain: config.trackingConfig?.customRedirectDomain,\n mailFromDomain,\n };\n}\n","import * as aws from \"@pulumi/aws\";\n\n/**\n * SQS resources output\n */\nexport type SQSResources = {\n queue: aws.sqs.Queue;\n dlq: aws.sqs.Queue;\n};\n\n/**\n * Create SQS queue with Dead Letter Queue for event processing\n *\n * Architecture:\n * EventBridge -> SQS Queue -> Lambda (event-processor)\n * ↓\n * DLQ (failed messages after 3 retries)\n */\nexport async function createSQSResources(): Promise<SQSResources> {\n // Dead Letter Queue for failed event processing\n const dlq = new aws.sqs.Queue(\"wraps-email-events-dlq\", {\n name: \"wraps-email-events-dlq\",\n messageRetentionSeconds: 1_209_600, // 14 days\n tags: {\n ManagedBy: \"wraps-cli\",\n Description: \"Dead letter queue for failed SES event processing\",\n },\n });\n\n // Main queue for SES events\n const queue = new aws.sqs.Queue(\"wraps-email-events\", {\n name: \"wraps-email-events\",\n visibilityTimeoutSeconds: 300, // 5 minutes (Lambda timeout)\n messageRetentionSeconds: 345_600, // 4 days\n receiveWaitTimeSeconds: 20, // Long polling\n redrivePolicy: dlq.arn.apply((arn) =>\n JSON.stringify({\n deadLetterTargetArn: arn,\n maxReceiveCount: 3, // Retry 3 times before sending to DLQ\n })\n ),\n tags: {\n ManagedBy: \"wraps-cli\",\n Description: \"Queue for SES email events from EventBridge\",\n },\n });\n\n return {\n queue,\n dlq,\n };\n}\n","import * as aws from \"@pulumi/aws\";\n\n/**\n * Vercel OIDC configuration\n */\nexport type VercelOIDCConfig = {\n teamSlug: string;\n accountId: string;\n};\n\n/**\n * Get existing OIDC provider ARN by URL\n */\nasync function getExistingOIDCProviderArn(url: string): Promise<string | null> {\n try {\n const { IAMClient, ListOpenIDConnectProvidersCommand } = await import(\n \"@aws-sdk/client-iam\"\n );\n // IAM is global but SDK still requires a region\n const iam = new IAMClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n\n const response = await iam.send(new ListOpenIDConnectProvidersCommand({}));\n\n // Find provider by ARN pattern (ARN includes the URL)\n // Format: arn:aws:iam::ACCOUNT:oidc-provider/oidc.vercel.com/TEAM\n const expectedArnSuffix = url.replace(\"https://\", \"\");\n const provider = response.OpenIDConnectProviderList?.find((p) =>\n p.Arn?.endsWith(expectedArnSuffix)\n );\n\n return provider?.Arn || null;\n } catch (error) {\n console.error(\"Error checking for existing OIDC provider:\", error);\n return null;\n }\n}\n\n/**\n * Create or get existing Vercel OIDC provider for AssumeRoleWithWebIdentity\n */\nexport async function createVercelOIDC(\n config: VercelOIDCConfig\n): Promise<aws.iam.OpenIdConnectProvider> {\n const url = `https://oidc.vercel.com/${config.teamSlug}`;\n\n // Check if OIDC provider already exists\n const existingArn = await getExistingOIDCProviderArn(url);\n\n if (existingArn) {\n // Import existing OIDC provider instead of creating new one\n return new aws.iam.OpenIdConnectProvider(\n \"wraps-vercel-oidc\",\n {\n url,\n clientIdLists: [`https://vercel.com/${config.teamSlug}`],\n thumbprintLists: [\n // Vercel OIDC thumbprints\n \"20032e77eca0785eece16b56b42c9b330b906320\",\n \"696db3af0dffc17e65c6a20d925c5a7bd24dec7e\",\n ],\n tags: {\n ManagedBy: \"wraps-cli\",\n Provider: \"vercel\",\n },\n },\n {\n import: existingArn, // Import existing resource\n }\n );\n }\n\n // Create new OIDC provider if it doesn't exist\n return new aws.iam.OpenIdConnectProvider(\"wraps-vercel-oidc\", {\n url,\n clientIdLists: [`https://vercel.com/${config.teamSlug}`],\n thumbprintLists: [\n // Vercel OIDC thumbprints\n \"20032e77eca0785eece16b56b42c9b330b906320\",\n \"696db3af0dffc17e65c6a20d925c5a7bd24dec7e\",\n ],\n tags: {\n ManagedBy: \"wraps-cli\",\n Provider: \"vercel\",\n },\n });\n}\n","import { exec } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport * as automation from \"@pulumi/pulumi/automation/index.js\";\nimport { errors } from \"./errors.js\";\n\nconst execAsync = promisify(exec);\n\n// Extract installPulumiCli from the automation module\nconst installPulumiCli = (automation as any).installPulumiCli;\n\n/**\n * Check if Pulumi CLI is installed\n */\nexport async function checkPulumiInstalled(): Promise<boolean> {\n try {\n await execAsync(\"pulumi version\");\n return true;\n } catch (_error) {\n return false;\n }\n}\n\n/**\n * Ensure Pulumi CLI is installed, auto-install if missing\n * @returns true if Pulumi was auto-installed, false if it was already installed\n */\nexport async function ensurePulumiInstalled(): Promise<boolean> {\n const isInstalled = await checkPulumiInstalled();\n\n if (!isInstalled) {\n try {\n // Try to auto-install Pulumi CLI using Automation API\n await installPulumiCli();\n return true; // Was auto-installed\n } catch (_error) {\n // If auto-install fails, throw helpful error\n throw errors.pulumiNotInstalled();\n }\n }\n\n return false; // Was already installed\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { deployEmailStack } from \"../../infrastructure/email-stack.js\";\nimport {\n trackError,\n trackServiceDeployed,\n trackServiceInit,\n} from \"../../telemetry/events.js\";\nimport type { ConnectOptions, EmailStackConfig } from \"../../types/index.js\";\nimport { getPreset } from \"../../utils/email/presets.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { errors } from \"../../utils/shared/errors.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n createConnectionMetadata,\n loadConnectionMetadata,\n saveConnectionMetadata,\n} from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayPreview,\n displaySuccess,\n} from \"../../utils/shared/output.js\";\nimport {\n confirmConnect,\n promptConfigPreset,\n promptProvider,\n promptRegion,\n promptSelectIdentities,\n promptVercelConfig,\n} from \"../../utils/shared/prompts.js\";\nimport { ensurePulumiInstalled } from \"../../utils/shared/pulumi.js\";\nimport { scanAWSResources } from \"../../utils/shared/scanner.js\";\n\n/**\n * Connect command - Connect to existing AWS SES infrastructure\n */\nexport async function connect(options: ConnectOptions): Promise<void> {\n const startTime = Date.now();\n\n clack.intro(\n pc.bold(\n options.preview\n ? \"Wraps Connect Preview\"\n : \"Wraps Connect - Link Existing Infrastructure\"\n )\n );\n\n const progress = new DeploymentProgress();\n\n // 1. Check Pulumi CLI is installed\n const wasAutoInstalled = await progress.execute(\n \"Checking Pulumi CLI installation\",\n async () => await ensurePulumiInstalled()\n );\n\n if (wasAutoInstalled) {\n progress.info(\"Pulumi CLI was automatically installed\");\n }\n\n // 2. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`Connected to AWS account: ${pc.cyan(identity.accountId)}`);\n\n // 3. Get region\n let region = options.region;\n if (!region) {\n const defaultRegion = await getAWSRegion();\n region = await promptRegion(defaultRegion);\n }\n\n // 4. Check if connection already exists\n const existingConnection = await loadConnectionMetadata(\n identity.accountId,\n region\n );\n if (existingConnection) {\n clack.log.warn(\n `Connection already exists for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n clack.log.info(`Created: ${existingConnection.timestamp}`);\n clack.log.info(`Use ${pc.cyan(\"wraps status\")} to view current setup`);\n clack.log.info(`Use ${pc.cyan(\"wraps upgrade\")} to add more features`);\n process.exit(0);\n }\n\n // 5. Scan existing AWS resources\n const scan = await progress.execute(\n \"Scanning existing AWS resources\",\n async () => scanAWSResources(region)\n );\n\n // Display what we found\n progress.info(\n `Found: ${scan.identities.length} identities, ${scan.configurationSets.length} config sets`\n );\n\n // Check if any identities exist\n if (scan.identities.length === 0) {\n clack.log.warn(\"No SES identities found in this region.\");\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} to create new email infrastructure instead.`\n );\n process.exit(0);\n }\n\n // Show verified identities\n const verifiedIdentities = scan.identities.filter((id) => id.verified);\n if (verifiedIdentities.length > 0) {\n progress.info(\n `Verified identities: ${verifiedIdentities.map((id) => pc.cyan(id.name)).join(\", \")}`\n );\n }\n\n // 6. Get provider configuration\n let provider = options.provider;\n if (!provider) {\n provider = await promptProvider();\n }\n\n // Get Vercel config if needed\n let vercelConfig;\n if (provider === \"vercel\") {\n vercelConfig = await promptVercelConfig();\n }\n\n // 7. Select identities to connect\n const selectedIdentities = await promptSelectIdentities(\n scan.identities.map((id) => ({\n name: id.name,\n verified: id.verified,\n }))\n );\n\n if (selectedIdentities.length === 0) {\n clack.log.warn(\"No identities selected. Nothing to connect.\");\n process.exit(0);\n }\n\n // 8. Select configuration preset\n const preset = await promptConfigPreset();\n const emailConfig =\n preset === \"custom\"\n ? await import(\"../../utils/shared/prompts.js\").then((m) =>\n m.promptCustomConfig()\n )\n : getPreset(preset)!;\n\n // 8a. Set the domain from the first selected identity (if it's a domain, not an email)\n // Filter to only domains (exclude email addresses)\n const domainIdentities = selectedIdentities.filter((id) => !id.includes(\"@\"));\n if (domainIdentities.length > 0) {\n emailConfig.domain = domainIdentities[0];\n }\n\n // 9. Confirm deployment (skip if --yes or --preview)\n if (!(options.yes || options.preview)) {\n const confirmed = await confirmConnect();\n if (!confirmed) {\n clack.cancel(\"Connection cancelled.\");\n process.exit(0);\n }\n }\n\n // 10. Build stack configuration\n const stackConfig: EmailStackConfig = {\n provider,\n region,\n vercel: vercelConfig,\n emailConfig,\n };\n\n // 11. Preview or Deploy infrastructure using Pulumi\n if (options.preview) {\n // PREVIEW MODE - show what would be created without deploying\n try {\n const previewResult = await progress.execute(\n \"Generating infrastructure preview\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName: `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Run preview instead of deployment\n const result = await stack.preview({ diff: true });\n return result;\n }\n );\n\n // Display preview results\n displayPreview({\n changeSummary: previewResult.changeSummary,\n commandName: \"wraps email connect\",\n });\n\n clack.outro(\n pc.green(\"Preview complete. Run without --preview to connect.\")\n );\n\n // Track preview completion\n trackServiceInit(\"email\", true, {\n preset,\n provider,\n preview: true,\n duration_ms: Date.now() - startTime,\n existing_identities: selectedIdentities.length,\n });\n return;\n } catch (error: any) {\n trackError(\"PREVIEW_FAILED\", \"email:connect\", { step: \"preview\" });\n if (error.message?.includes(\"stack is currently locked\")) {\n throw errors.stackLocked();\n }\n throw new Error(`Preview failed: ${error.message}`);\n }\n }\n\n // DEPLOY MODE - actually create infrastructure\n let outputs;\n try {\n outputs = await progress.execute(\n \"Deploying Wraps infrastructure (this may take 2-3 minutes)\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName: `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.workspace.selectStack(\n `wraps-${identity.accountId}-${region}`\n );\n await stack.setConfig(\"aws:region\", { value: region });\n\n const upResult = await stack.up({ onOutput: () => {} });\n const pulumiOutputs = upResult.outputs;\n\n return {\n roleArn: pulumiOutputs.roleArn?.value as string,\n configSetName: pulumiOutputs.configSetName?.value as\n | string\n | undefined,\n tableName: pulumiOutputs.tableName?.value as string | undefined,\n region: pulumiOutputs.region?.value as string,\n lambdaFunctions: pulumiOutputs.lambdaFunctions?.value as\n | string[]\n | undefined,\n domain: pulumiOutputs.domain?.value as string | undefined,\n dkimTokens: pulumiOutputs.dkimTokens?.value as string[] | undefined,\n customTrackingDomain: pulumiOutputs.customTrackingDomain?.value as\n | string\n | undefined,\n };\n }\n );\n } catch (error: any) {\n // Track deployment failure\n trackServiceInit(\"email\", false, {\n preset,\n provider,\n duration_ms: Date.now() - startTime,\n });\n\n // Check if it's a lock file error\n if (error.message?.includes(\"stack is currently locked\")) {\n trackError(\"STACK_LOCKED\", \"email:connect\", { step: \"deploy\" });\n throw errors.stackLocked();\n }\n\n trackError(\"DEPLOYMENT_FAILED\", \"email:connect\", { step: \"deploy\" });\n throw new Error(`Pulumi deployment failed: ${error.message}`);\n }\n\n // 12. Create DNS records in Route53 (if hosted zone exists)\n if (outputs.domain && outputs.dkimTokens && outputs.dkimTokens.length > 0) {\n const { findHostedZone, createDNSRecords } = await import(\n \"../../utils/route53.js\"\n );\n const hostedZone = await findHostedZone(outputs.domain, region);\n\n if (hostedZone) {\n try {\n progress.start(\"Creating DNS records in Route53\");\n\n // Determine mailFromDomain - use outputs if available, otherwise construct default\n const mailFromDomain =\n emailConfig.mailFromDomain || `mail.${outputs.domain}`;\n\n await createDNSRecords(\n hostedZone.id,\n outputs.domain,\n outputs.dkimTokens,\n region,\n outputs.customTrackingDomain,\n mailFromDomain\n );\n progress.succeed(\"DNS records created in Route53\");\n } catch (error: any) {\n progress.fail(\n `Failed to create DNS records automatically: ${error.message}`\n );\n progress.info(\n \"You can manually add the required DNS records shown below\"\n );\n }\n }\n }\n\n // 13. Save metadata\n const metadata = createConnectionMetadata(\n identity.accountId,\n region,\n provider,\n emailConfig,\n preset === \"custom\" ? undefined : preset\n );\n if (metadata.services.email) {\n metadata.services.email.pulumiStackName = `wraps-${identity.accountId}-${region}`;\n }\n if (vercelConfig) {\n metadata.vercel = vercelConfig;\n }\n await saveConnectionMetadata(metadata);\n\n progress.info(\"Connection metadata saved\");\n\n // 14. Display success message\n displaySuccess({\n roleArn: outputs.roleArn,\n configSetName: outputs.configSetName,\n region: outputs.region!,\n tableName: outputs.tableName,\n });\n\n // Show next steps\n if (selectedIdentities.length > 0 && emailConfig.tracking?.enabled) {\n console.log(`\\n${pc.bold(\"Next Steps:\")}\\n`);\n console.log(\n `Update your code to use configuration set: ${pc.cyan(\"wraps-email-tracking\")}`\n );\n console.log(`\\n${pc.dim(\"Example:\")}`);\n console.log(\n pc.gray(` await ses.sendEmail({\n ConfigurationSetName: 'wraps-email-tracking',\n // ... other parameters\n });`)\n );\n console.log(\"\");\n }\n\n // 15. Track successful connection\n const duration = Date.now() - startTime;\n const enabledFeatures: string[] = [];\n if (emailConfig.tracking?.enabled) enabledFeatures.push(\"tracking\");\n if (emailConfig.suppressionList?.enabled)\n enabledFeatures.push(\"suppression_list\");\n if (emailConfig.eventTracking?.enabled)\n enabledFeatures.push(\"event_tracking\");\n if (emailConfig.eventTracking?.dynamoDBHistory)\n enabledFeatures.push(\"dynamodb_history\");\n\n trackServiceInit(\"email\", true, {\n preset,\n provider,\n features: enabledFeatures,\n duration_ms: duration,\n existing_identities: selectedIdentities.length,\n });\n\n trackServiceDeployed(\"email\", {\n duration_ms: duration,\n features: enabledFeatures,\n preset,\n });\n}\n","import {\n DescribeTableCommand,\n DynamoDBClient,\n ListTablesCommand,\n} from \"@aws-sdk/client-dynamodb\";\nimport { IAMClient, ListRolesCommand } from \"@aws-sdk/client-iam\";\nimport { LambdaClient, ListFunctionsCommand } from \"@aws-sdk/client-lambda\";\nimport {\n DescribeConfigurationSetCommand,\n GetIdentityVerificationAttributesCommand,\n ListConfigurationSetsCommand,\n ListIdentitiesCommand,\n SESClient,\n} from \"@aws-sdk/client-ses\";\nimport {\n GetTopicAttributesCommand,\n ListTopicsCommand,\n SNSClient,\n} from \"@aws-sdk/client-sns\";\n\n/**\n * SES Identity with configuration\n */\nexport type SESIdentity = {\n name: string;\n type: \"Domain\" | \"EmailAddress\";\n verified: boolean;\n configurationSet?: string;\n dkimEnabled?: boolean;\n};\n\n/**\n * SES Configuration Set\n */\nexport type SESConfigurationSet = {\n name: string;\n eventDestinations: Array<{\n name: string;\n enabled: boolean;\n matchingEventTypes: string[];\n snsDestination?: string;\n cloudWatchDestination?: any;\n }>;\n};\n\n/**\n * SNS Topic\n */\nexport type SNSTopic = {\n arn: string;\n name: string;\n subscriptions?: number;\n};\n\n/**\n * DynamoDB Table\n */\nexport type DynamoTable = {\n name: string;\n status: string;\n itemCount?: number;\n sizeBytes?: number;\n};\n\n/**\n * Lambda Function\n */\nexport type LambdaFunction = {\n name: string;\n arn: string;\n runtime?: string;\n handler?: string;\n};\n\n/**\n * IAM Role\n */\nexport type IAMRole = {\n name: string;\n arn: string;\n assumeRolePolicyDocument: string;\n};\n\n/**\n * Complete scan of existing AWS resources\n */\nexport type AWSResourceScan = {\n identities: SESIdentity[];\n configurationSets: SESConfigurationSet[];\n snsTopics: SNSTopic[];\n dynamoTables: DynamoTable[];\n lambdaFunctions: LambdaFunction[];\n iamRoles: IAMRole[];\n};\n\n/**\n * Scan all existing SES identities (domains and email addresses)\n */\nexport async function scanSESIdentities(\n region: string\n): Promise<SESIdentity[]> {\n const ses = new SESClient({ region });\n const identities: SESIdentity[] = [];\n\n try {\n // List all identities\n const listResponse = await ses.send(new ListIdentitiesCommand({}));\n const identityNames = listResponse.Identities || [];\n\n if (identityNames.length === 0) {\n return [];\n }\n\n // Get verification attributes\n const attrsResponse = await ses.send(\n new GetIdentityVerificationAttributesCommand({\n Identities: identityNames,\n })\n );\n\n const attrs = attrsResponse.VerificationAttributes || {};\n\n // Build identity objects\n for (const name of identityNames) {\n const attr = attrs[name];\n identities.push({\n name,\n type: name.includes(\"@\") ? \"EmailAddress\" : \"Domain\",\n verified: attr?.VerificationStatus === \"Success\",\n });\n }\n\n return identities;\n } catch (error: any) {\n console.error(\"Error scanning SES identities:\", error.message);\n return [];\n }\n}\n\n/**\n * Scan all SES configuration sets\n */\nexport async function scanSESConfigurationSets(\n region: string\n): Promise<SESConfigurationSet[]> {\n const ses = new SESClient({ region });\n const configSets: SESConfigurationSet[] = [];\n\n try {\n // List configuration sets\n const listResponse = await ses.send(new ListConfigurationSetsCommand({}));\n const configSetNames =\n listResponse.ConfigurationSets?.map((cs) => cs.Name!).filter(Boolean) ||\n [];\n\n // Get details for each config set\n for (const name of configSetNames) {\n try {\n const describeResponse = await ses.send(\n new DescribeConfigurationSetCommand({ ConfigurationSetName: name })\n );\n\n const eventDestinations =\n describeResponse.EventDestinations?.map((ed) => ({\n name: ed.Name!,\n enabled: ed.Enabled ?? false,\n matchingEventTypes: ed.MatchingEventTypes || [],\n snsDestination: ed.SNSDestination?.TopicARN,\n cloudWatchDestination: ed.CloudWatchDestination,\n })) || [];\n\n configSets.push({\n name,\n eventDestinations,\n });\n } catch (error: any) {\n console.error(`Error describing config set ${name}:`, error.message);\n }\n }\n\n return configSets;\n } catch (error: any) {\n console.error(\"Error scanning SES configuration sets:\", error.message);\n return [];\n }\n}\n\n/**\n * Scan SNS topics (filter for email-related ones)\n */\nexport async function scanSNSTopics(region: string): Promise<SNSTopic[]> {\n const sns = new SNSClient({ region });\n const topics: SNSTopic[] = [];\n\n try {\n // List all topics\n const listResponse = await sns.send(new ListTopicsCommand({}));\n const topicArns =\n listResponse.Topics?.map((t) => t.TopicArn!).filter(Boolean) || [];\n\n // Get details for each topic\n for (const arn of topicArns) {\n try {\n const attrsResponse = await sns.send(\n new GetTopicAttributesCommand({ TopicArn: arn })\n );\n\n const name = arn.split(\":\").pop() || arn;\n const subscriptions = Number.parseInt(\n attrsResponse.Attributes?.SubscriptionsConfirmed || \"0\",\n 10\n );\n\n topics.push({\n arn,\n name,\n subscriptions,\n });\n } catch (error: any) {\n console.error(\n `Error getting topic attributes for ${arn}:`,\n error.message\n );\n }\n }\n\n return topics;\n } catch (error: any) {\n console.error(\"Error scanning SNS topics:\", error.message);\n return [];\n }\n}\n\n/**\n * Scan DynamoDB tables (filter for email-related ones)\n */\nexport async function scanDynamoTables(region: string): Promise<DynamoTable[]> {\n const dynamo = new DynamoDBClient({ region });\n const tables: DynamoTable[] = [];\n\n try {\n // List all tables\n const listResponse = await dynamo.send(new ListTablesCommand({}));\n const tableNames = listResponse.TableNames || [];\n\n // Get details for each table\n for (const name of tableNames) {\n try {\n const describeResponse = await dynamo.send(\n new DescribeTableCommand({ TableName: name })\n );\n\n const table = describeResponse.Table;\n if (table) {\n tables.push({\n name,\n status: table.TableStatus || \"UNKNOWN\",\n itemCount: table.ItemCount,\n sizeBytes: table.TableSizeBytes,\n });\n }\n } catch (error: any) {\n console.error(`Error describing table ${name}:`, error.message);\n }\n }\n\n return tables;\n } catch (error: any) {\n console.error(\"Error scanning DynamoDB tables:\", error.message);\n return [];\n }\n}\n\n/**\n * Scan Lambda functions (filter for email-related ones)\n */\nexport async function scanLambdaFunctions(\n region: string\n): Promise<LambdaFunction[]> {\n const lambda = new LambdaClient({ region });\n const functions: LambdaFunction[] = [];\n\n try {\n // List all functions\n const listResponse = await lambda.send(new ListFunctionsCommand({}));\n const functionConfigs = listResponse.Functions || [];\n\n for (const func of functionConfigs) {\n if (func.FunctionName && func.FunctionArn) {\n functions.push({\n name: func.FunctionName,\n arn: func.FunctionArn,\n runtime: func.Runtime,\n handler: func.Handler,\n });\n }\n }\n\n return functions;\n } catch (error: any) {\n console.error(\"Error scanning Lambda functions:\", error.message);\n return [];\n }\n}\n\n/**\n * Scan IAM roles (filter for Wraps or email-related ones)\n */\nexport async function scanIAMRoles(region: string): Promise<IAMRole[]> {\n const iam = new IAMClient({ region });\n const roles: IAMRole[] = [];\n\n try {\n // List all roles (with pagination support)\n let marker: string | undefined;\n let hasMore = true;\n\n while (hasMore) {\n const listResponse = await iam.send(\n new ListRolesCommand({\n Marker: marker,\n MaxItems: 100,\n })\n );\n\n const roleList = listResponse.Roles || [];\n\n for (const role of roleList) {\n if (role.RoleName && role.Arn) {\n roles.push({\n name: role.RoleName,\n arn: role.Arn,\n assumeRolePolicyDocument: role.AssumeRolePolicyDocument || \"\",\n });\n }\n }\n\n marker = listResponse.Marker;\n hasMore = listResponse.IsTruncated ?? false;\n }\n\n return roles;\n } catch (error: any) {\n console.error(\"Error scanning IAM roles:\", error.message);\n return [];\n }\n}\n\n/**\n * Scan all relevant AWS resources for email infrastructure\n */\nexport async function scanAWSResources(\n region: string\n): Promise<AWSResourceScan> {\n const [\n identities,\n configurationSets,\n snsTopics,\n dynamoTables,\n lambdaFunctions,\n iamRoles,\n ] = await Promise.all([\n scanSESIdentities(region),\n scanSESConfigurationSets(region),\n scanSNSTopics(region),\n scanDynamoTables(region),\n scanLambdaFunctions(region),\n scanIAMRoles(region),\n ]);\n\n return {\n identities,\n configurationSets,\n snsTopics,\n dynamoTables,\n lambdaFunctions,\n iamRoles,\n };\n}\n\n/**\n * Filter resources to only Wraps-managed ones (wraps-* prefix)\n */\nexport function filterWrapsResources(scan: AWSResourceScan): AWSResourceScan {\n return {\n identities: scan.identities, // All identities are relevant\n configurationSets: scan.configurationSets.filter((cs) =>\n cs.name.startsWith(\"wraps-\")\n ),\n snsTopics: scan.snsTopics.filter((t) => t.name.startsWith(\"wraps-\")),\n dynamoTables: scan.dynamoTables.filter((t) => t.name.startsWith(\"wraps-\")),\n lambdaFunctions: scan.lambdaFunctions.filter((f) =>\n f.name.startsWith(\"wraps-\")\n ),\n iamRoles: scan.iamRoles.filter((r) => r.name.startsWith(\"wraps-\")),\n };\n}\n\n/**\n * Check if specific Wraps resources exist\n */\nexport function checkWrapsResourcesExist(scan: AWSResourceScan): {\n hasConfigSet: boolean;\n hasSNSTopics: boolean;\n hasDynamoTable: boolean;\n hasLambdaFunctions: boolean;\n hasIAMRole: boolean;\n} {\n const filtered = filterWrapsResources(scan);\n\n return {\n hasConfigSet: filtered.configurationSets.length > 0,\n hasSNSTopics: filtered.snsTopics.length > 0,\n hasDynamoTable: filtered.dynamoTables.length > 0,\n hasLambdaFunctions: filtered.lambdaFunctions.length > 0,\n hasIAMRole: filtered.iamRoles.length > 0,\n };\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { trackError, trackServiceRemoved } from \"../../telemetry/events.js\";\nimport type { DestroyOptions } from \"../../types/index.js\";\nimport { deleteDNSRecords, findHostedZone } from \"../../utils/route53.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { errors } from \"../../utils/shared/errors.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n deleteConnectionMetadata,\n findConnectionsWithService,\n loadConnectionMetadata,\n} from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayPreview,\n} from \"../../utils/shared/output.js\";\n\n/**\n * Get DKIM tokens and MAIL FROM domain for a domain from SES\n */\nasync function getEmailIdentityInfo(\n domain: string,\n region: string\n): Promise<{ dkimTokens: string[]; mailFromDomain?: string }> {\n try {\n const { SESv2Client, GetEmailIdentityCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n const ses = new SESv2Client({ region });\n\n const response = await ses.send(\n new GetEmailIdentityCommand({ EmailIdentity: domain })\n );\n\n return {\n dkimTokens: response.DkimAttributes?.Tokens || [],\n mailFromDomain: response.MailFromAttributes?.MailFromDomain,\n };\n } catch (_error) {\n return { dkimTokens: [] };\n }\n}\n\n/**\n * Email Destroy command - Remove email infrastructure\n */\nexport async function emailDestroy(options: DestroyOptions): Promise<void> {\n const startTime = Date.now();\n\n clack.intro(\n pc.bold(\n options.preview\n ? \"Email Infrastructure Destruction Preview\"\n : \"Email Infrastructure Teardown\"\n )\n );\n\n const progress = new DeploymentProgress();\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region - check flag, then env, then metadata, then default\n let region = options.region || (await getAWSRegion());\n\n // If using default region (us-east-1), check if we have metadata for other regions\n if (\n !(\n options.region ||\n process.env.AWS_REGION ||\n process.env.AWS_DEFAULT_REGION\n )\n ) {\n const emailConnections = await findConnectionsWithService(\n identity.accountId,\n \"email\"\n );\n\n if (emailConnections.length === 1) {\n // Auto-select the only available region\n region = emailConnections[0].region;\n } else if (emailConnections.length > 1) {\n // Multiple regions found - prompt user to select\n const selectedRegion = await clack.select({\n message: \"Multiple email deployments found. Which region to destroy?\",\n options: emailConnections.map((conn) => ({\n value: conn.region,\n label: conn.region,\n })),\n });\n\n if (clack.isCancel(selectedRegion)) {\n clack.cancel(\"Operation cancelled\");\n process.exit(0);\n }\n\n region = selectedRegion as string;\n }\n }\n\n // 3. Load connection metadata to get domain info and stack name\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n const emailService = metadata?.services?.email;\n const emailConfig = emailService?.config;\n const domain = emailConfig?.domain;\n const storedStackName = emailService?.pulumiStackName;\n\n // 4. Confirm destruction (skip if --force or --preview)\n if (!(options.force || options.preview)) {\n const confirmed = await clack.confirm({\n message: pc.red(\n \"Are you sure you want to destroy all email infrastructure?\"\n ),\n initialValue: false,\n });\n\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel(\"Destruction cancelled.\");\n process.exit(0);\n }\n }\n\n // 5. Check for Route53 hosted zone and offer to clean up DNS\n let shouldCleanDNS = false;\n let hostedZone: { id: string; name: string } | null = null;\n let dkimTokens: string[] = [];\n // Get mailFromDomain from metadata, or fall back to querying SES\n let mailFromDomain = emailConfig?.mailFromDomain;\n\n if (domain && !options.preview) {\n hostedZone = await findHostedZone(domain, region);\n\n if (hostedZone) {\n // Get DKIM tokens and MAIL FROM domain from SES before we destroy\n const identityInfo = await getEmailIdentityInfo(domain, region);\n dkimTokens = identityInfo.dkimTokens;\n // Use MAIL FROM from SES if not in metadata (handles legacy deployments)\n if (!mailFromDomain && identityInfo.mailFromDomain) {\n mailFromDomain = identityInfo.mailFromDomain;\n }\n\n if (options.force) {\n shouldCleanDNS = true; // Auto-clean with --force\n } else {\n const cleanDNS = await clack.confirm({\n message: `Found Route53 hosted zone for ${pc.cyan(domain)}. Delete DNS records (DKIM, DMARC, MAIL FROM)?`,\n initialValue: true,\n });\n\n if (clack.isCancel(cleanDNS)) {\n clack.cancel(\"Destruction cancelled.\");\n process.exit(0);\n }\n\n shouldCleanDNS = cleanDNS;\n }\n }\n }\n\n // 6. Preview or Destroy infrastructure using Pulumi\n if (options.preview) {\n // PREVIEW MODE - show what would be destroyed without actually destroying\n try {\n const previewResult = await progress.execute(\n \"Generating destruction preview\",\n async () => {\n await ensurePulumiWorkDir();\n\n // Use stored stack name from metadata, fallback to generated name\n const stackName =\n storedStackName || `wraps-email-${identity.accountId}-${region}`;\n\n // Try to select the stack\n let stack;\n try {\n stack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName,\n workDir: getPulumiWorkDir(),\n });\n } catch (_error) {\n throw new Error(\"No email infrastructure found to preview\");\n }\n\n // Run preview to see what would be destroyed\n const result = await stack.preview({ diff: true });\n return result;\n }\n );\n\n // Display preview results\n displayPreview({\n changeSummary: previewResult.changeSummary,\n costEstimate: \"Monthly cost after destruction: $0.00\",\n commandName: \"wraps email destroy\",\n });\n\n // Show DNS cleanup info\n if (domain) {\n const previewHostedZone = await findHostedZone(domain, region);\n if (previewHostedZone) {\n clack.log.info(\n `DNS records in Route53 for ${pc.cyan(domain)} will also be deleted`\n );\n }\n }\n\n clack.outro(\n pc.green(\"Preview complete. Run without --preview to destroy.\")\n );\n\n // Track preview completion\n trackServiceRemoved(\"email\", {\n preview: true,\n region,\n duration_ms: Date.now() - startTime,\n });\n return;\n } catch (error: any) {\n progress.stop();\n if (error.message.includes(\"No email infrastructure found\")) {\n clack.log.warn(\"No email infrastructure found to preview\");\n process.exit(0);\n }\n trackError(\"PREVIEW_FAILED\", \"email destroy\", { step: \"preview\" });\n throw new Error(`Preview failed: ${error.message}`);\n }\n }\n\n // DESTROY MODE - actually remove infrastructure\n\n // 7. Clean up DNS records first (before destroying SES identity)\n if (shouldCleanDNS && hostedZone && domain && dkimTokens.length > 0) {\n try {\n await progress.execute(`Deleting DNS records for ${domain}`, async () => {\n await deleteDNSRecords(\n hostedZone.id,\n domain,\n dkimTokens,\n region,\n emailConfig?.tracking?.customRedirectDomain,\n mailFromDomain\n );\n });\n } catch (error: any) {\n clack.log.warn(`Could not delete DNS records: ${error.message}`);\n clack.log.info(\"You may need to delete them manually from Route53\");\n }\n }\n\n // 8. Destroy Pulumi infrastructure\n try {\n await progress.execute(\n \"Destroying email infrastructure (this may take 2-3 minutes)\",\n async () => {\n // Ensure Pulumi workspace directory exists\n await ensurePulumiWorkDir();\n\n // Use stored stack name from metadata, fallback to generated name\n const stackName =\n storedStackName || `wraps-email-${identity.accountId}-${region}`;\n\n // Try to select the stack\n let stack;\n try {\n stack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName,\n workDir: getPulumiWorkDir(),\n });\n } catch (_error) {\n throw new Error(\"No email infrastructure found to destroy\");\n }\n\n // Run destroy\n await stack.destroy({ onOutput: () => {} }); // Suppress Pulumi output\n\n // Remove the stack from workspace\n await stack.workspace.removeStack(stackName);\n }\n );\n } catch (error: any) {\n progress.stop();\n if (error.message.includes(\"No email infrastructure found\")) {\n clack.log.warn(\"No email infrastructure found\");\n // Still delete metadata if it exists\n await deleteConnectionMetadata(identity.accountId, region);\n process.exit(0);\n }\n // Check if it's a lock file error\n if (error.message?.includes(\"stack is currently locked\")) {\n trackError(\"STACK_LOCKED\", \"email destroy\", { step: \"destroy\" });\n throw errors.stackLocked();\n }\n trackError(\"DESTROY_FAILED\", \"email destroy\", { step: \"destroy\" });\n clack.log.error(\"Email infrastructure destruction failed\");\n throw error;\n }\n\n // 9. Delete connection metadata\n await deleteConnectionMetadata(identity.accountId, region);\n\n // 10. Display success message\n progress.stop();\n\n const deletedItems = [\"AWS infrastructure\"];\n if (shouldCleanDNS && hostedZone) {\n deletedItems.push(\"Route53 DNS records\");\n }\n\n clack.outro(pc.green(\"Email infrastructure has been removed\"));\n\n if (domain) {\n console.log(`\\n${pc.bold(\"Cleaned up:\")}`);\n for (const item of deletedItems) {\n console.log(` ${pc.green(\"✓\")} ${item}`);\n }\n\n // Remind about SPF record\n console.log(\n `\\n${pc.dim(\"Note: SPF record was not deleted. Remove 'include:amazonses.com' manually if needed.\")}`\n );\n }\n\n console.log(\n `\\nRun ${pc.cyan(\"wraps email init\")} to deploy infrastructure again.\\n`\n );\n\n // 11. Track successful destruction\n trackServiceRemoved(\"email\", {\n reason: \"user_initiated\",\n region,\n duration_ms: Date.now() - startTime,\n dns_cleaned: shouldCleanDNS,\n });\n}\n","import { Resolver } from \"node:dns/promises\";\nimport { GetEmailIdentityCommand, SESv2Client } from \"@aws-sdk/client-sesv2\";\nimport * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { trackCommand, trackFeature } from \"../../telemetry/events.js\";\nimport type { EmailVerifyOptions } from \"../../types/index.js\";\nimport { getAWSRegion } from \"../../utils/shared/aws.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\n\n/**\n * Verify domain DNS records and verification status\n */\nexport async function verifyDomain(options: EmailVerifyOptions): Promise<void> {\n clack.intro(pc.bold(`Verifying ${options.domain}`));\n\n const progress = new DeploymentProgress();\n const region = await getAWSRegion();\n\n // 1. Check SES verification status\n const sesClient = new SESv2Client({ region });\n let identity;\n let dkimTokens: string[] = [];\n let mailFromDomain: string | undefined;\n\n try {\n identity = await progress.execute(\n \"Checking SES verification status\",\n async () => {\n const response = await sesClient.send(\n new GetEmailIdentityCommand({ EmailIdentity: options.domain })\n );\n return response;\n }\n );\n\n dkimTokens = identity.DkimAttributes?.Tokens || [];\n mailFromDomain = identity.MailFromAttributes?.MailFromDomain;\n } catch (_error: any) {\n progress.stop();\n clack.log.error(`Domain ${options.domain} not found in SES`);\n console.log(\n `\\nRun ${pc.cyan(`wraps email init --domain ${options.domain}`)} to add this domain.\\n`\n );\n process.exit(1);\n return; // Return after process.exit for testing\n }\n\n // 2. Check DNS records\n const resolver = new Resolver();\n // Use public DNS servers for more reliable results\n resolver.setServers([\"8.8.8.8\", \"1.1.1.1\"]);\n const dnsResults: Array<{\n name: string;\n type: string;\n status: string;\n records?: string[];\n }> = [];\n\n // Check DKIM records\n for (const token of dkimTokens) {\n const dkimRecord = `${token}._domainkey.${options.domain}`;\n try {\n const records = await resolver.resolveCname(dkimRecord);\n const expected = `${token}.dkim.amazonses.com`;\n const found = records.some((r) => r === expected || r === `${expected}.`);\n dnsResults.push({\n name: dkimRecord,\n type: \"CNAME\",\n status: found ? \"verified\" : \"incorrect\",\n records,\n });\n } catch (_error) {\n dnsResults.push({\n name: dkimRecord,\n type: \"CNAME\",\n status: \"missing\",\n });\n }\n }\n\n // Check SPF record\n try {\n const records = await resolver.resolveTxt(options.domain);\n const spfRecord = records.flat().find((r) => r.startsWith(\"v=spf1\"));\n const hasAmazonSES = spfRecord?.includes(\"include:amazonses.com\");\n dnsResults.push({\n name: options.domain,\n type: \"TXT (SPF)\",\n status: hasAmazonSES ? \"verified\" : spfRecord ? \"incorrect\" : \"missing\",\n records: spfRecord ? [spfRecord] : undefined,\n });\n } catch (_error) {\n dnsResults.push({\n name: options.domain,\n type: \"TXT (SPF)\",\n status: \"missing\",\n });\n }\n\n // Check DMARC record\n try {\n const records = await resolver.resolveTxt(`_dmarc.${options.domain}`);\n const dmarcRecord = records.flat().find((r) => r.startsWith(\"v=DMARC1\"));\n dnsResults.push({\n name: `_dmarc.${options.domain}`,\n type: \"TXT (DMARC)\",\n status: dmarcRecord ? \"verified\" : \"missing\",\n records: dmarcRecord ? [dmarcRecord] : undefined,\n });\n } catch (_error) {\n dnsResults.push({\n name: `_dmarc.${options.domain}`,\n type: \"TXT (DMARC)\",\n status: \"missing\",\n });\n }\n\n // Check MAIL FROM domain records (if configured)\n if (mailFromDomain) {\n // Check MX record for MAIL FROM domain\n try {\n const mxRecords = await resolver.resolveMx(mailFromDomain);\n const expectedMx = `feedback-smtp.${region}.amazonses.com`;\n const hasMx = mxRecords.some(\n (r) => r.exchange === expectedMx || r.exchange === `${expectedMx}.`\n );\n dnsResults.push({\n name: mailFromDomain,\n type: \"MX\",\n status: hasMx\n ? \"verified\"\n : mxRecords.length > 0\n ? \"incorrect\"\n : \"missing\",\n records: mxRecords.map((r) => `${r.priority} ${r.exchange}`),\n });\n } catch (_error) {\n dnsResults.push({\n name: mailFromDomain,\n type: \"MX\",\n status: \"missing\",\n });\n }\n\n // Check SPF record for MAIL FROM domain\n try {\n const records = await resolver.resolveTxt(mailFromDomain);\n const spfRecord = records.flat().find((r) => r.startsWith(\"v=spf1\"));\n const hasAmazonSES = spfRecord?.includes(\"include:amazonses.com\");\n dnsResults.push({\n name: mailFromDomain,\n type: \"TXT (SPF)\",\n status: hasAmazonSES ? \"verified\" : spfRecord ? \"incorrect\" : \"missing\",\n records: spfRecord ? [spfRecord] : undefined,\n });\n } catch (_error) {\n dnsResults.push({\n name: mailFromDomain,\n type: \"TXT (SPF)\",\n status: \"missing\",\n });\n }\n }\n\n progress.stop();\n\n // 3. Display results\n const verificationStatus = identity.VerifiedForSendingStatus\n ? \"verified\"\n : \"pending\";\n const dkimStatus = identity.DkimAttributes?.Status || \"PENDING\";\n const mailFromStatus =\n identity.MailFromAttributes?.MailFromDomainStatus || \"NOT_CONFIGURED\";\n\n const statusLines = [\n `${pc.bold(\"Domain:\")} ${options.domain}`,\n `${pc.bold(\"Verification Status:\")} ${\n verificationStatus === \"verified\"\n ? pc.green(\"✓ Verified\")\n : pc.yellow(\"⏱ Pending\")\n }`,\n `${pc.bold(\"DKIM Status:\")} ${\n dkimStatus === \"SUCCESS\"\n ? pc.green(\"✓ Success\")\n : pc.yellow(`⏱ ${dkimStatus}`)\n }`,\n ];\n\n if (mailFromDomain) {\n statusLines.push(\n `${pc.bold(\"MAIL FROM Domain:\")} ${mailFromDomain}`,\n `${pc.bold(\"MAIL FROM Status:\")} ${\n mailFromStatus === \"SUCCESS\"\n ? pc.green(\"✓ Success\")\n : mailFromStatus === \"NOT_CONFIGURED\"\n ? pc.yellow(\"⏱ Not Configured\")\n : pc.yellow(`⏱ ${mailFromStatus}`)\n }`\n );\n }\n\n clack.note(statusLines.join(\"\\n\"), \"SES Status\");\n\n // DNS Records\n const dnsLines = dnsResults.map((record) => {\n let statusIcon: string;\n let statusColor: (s: string) => string;\n\n if (record.status === \"verified\") {\n statusIcon = \"✓\";\n statusColor = pc.green;\n } else if (record.status === \"incorrect\") {\n statusIcon = \"✗\";\n statusColor = pc.red;\n } else {\n statusIcon = \"✗\";\n statusColor = pc.red;\n }\n\n const recordInfo = record.records ? ` → ${record.records.join(\", \")}` : \"\";\n return ` ${statusColor(statusIcon)} ${record.name} (${record.type}) ${statusColor(\n record.status\n )}${recordInfo}`;\n });\n\n clack.note(dnsLines.join(\"\\n\"), \"DNS Records\");\n\n // Summary\n const allVerified = dnsResults.every((r) => r.status === \"verified\");\n const someIncorrect = dnsResults.some((r) => r.status === \"incorrect\");\n\n if (verificationStatus === \"verified\" && allVerified) {\n clack.outro(\n pc.green(\"✓ Domain is fully verified and ready to send emails!\")\n );\n trackFeature(\"domain_verified\", { dns_auto_detected: true });\n } else if (someIncorrect) {\n clack.outro(\n pc.red(\"✗ Some DNS records are incorrect. Please update them.\")\n );\n console.log(\n `\\nRun ${pc.cyan(\"wraps email status\")} to see the correct DNS records.\\n`\n );\n } else {\n clack.outro(\n pc.yellow(\"⏱ Waiting for DNS propagation and SES verification\")\n );\n console.log(\"\\nDNS records can take up to 48 hours to propagate.\");\n console.log(\n \"SES verification usually completes within 72 hours after DNS propagation.\\n\"\n );\n }\n\n // Track verify command\n trackCommand(\"email:domains:verify\", {\n success: true,\n verified: verificationStatus === \"verified\" && allVerified,\n dkim_status: dkimStatus,\n });\n}\n\n/**\n * Add a domain to SES for email sending\n */\nexport async function addDomain(options: { domain: string }): Promise<void> {\n clack.intro(pc.bold(`Adding domain ${options.domain} to SES`));\n\n const progress = new DeploymentProgress();\n const region = await getAWSRegion();\n const sesClient = new SESv2Client({ region });\n\n try {\n // Check if domain already exists\n try {\n await sesClient.send(\n new GetEmailIdentityCommand({ EmailIdentity: options.domain })\n );\n progress.stop();\n clack.log.warn(`Domain ${options.domain} already exists in SES`);\n console.log(\n `\\nRun ${pc.cyan(`wraps email domains verify --domain ${options.domain}`)} to check verification status.\\n`\n );\n return;\n } catch (error: any) {\n // Domain doesn't exist, continue with creation\n if (error.name !== \"NotFoundException\") {\n throw error;\n }\n }\n\n // Create the email identity\n const { CreateEmailIdentityCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n await progress.execute(\"Adding domain to SES\", async () => {\n await sesClient.send(\n new CreateEmailIdentityCommand({\n EmailIdentity: options.domain,\n DkimSigningAttributes: {\n NextSigningKeyLength: \"RSA_2048_BIT\",\n },\n })\n );\n });\n\n // Get the DKIM tokens\n const identity = await sesClient.send(\n new GetEmailIdentityCommand({ EmailIdentity: options.domain })\n );\n const dkimTokens = identity.DkimAttributes?.Tokens || [];\n\n progress.stop();\n\n clack.outro(pc.green(`✓ Domain ${options.domain} added successfully!`));\n\n // Show next steps\n console.log(`\\n${pc.bold(\"Next steps:\")}\\n`);\n console.log(\"1. Add the following DKIM records to your DNS:\\n\");\n\n for (const token of dkimTokens) {\n console.log(` ${pc.cyan(`${token}._domainkey.${options.domain}`)}`);\n console.log(\n ` ${pc.dim(\"Type:\")} CNAME ${pc.dim(\"Value:\")} ${token}.dkim.amazonses.com\\n`\n );\n }\n\n console.log(\n `2. Verify DNS propagation: ${pc.cyan(`wraps email domains verify --domain ${options.domain}`)}`\n );\n console.log(`3. Check status: ${pc.cyan(\"wraps email status\")}\\n`);\n\n // Track add domain success\n trackCommand(\"email:domains:add\", {\n success: true,\n });\n trackFeature(\"domain_added\", {});\n } catch (error: any) {\n progress.stop();\n trackCommand(\"email:domains:add\", {\n success: false,\n });\n throw error;\n }\n}\n\n/**\n * List all domains configured in SES\n */\nexport async function listDomains(): Promise<void> {\n clack.intro(pc.bold(\"SES Email Domains\"));\n\n const progress = new DeploymentProgress();\n const region = await getAWSRegion();\n const sesClient = new SESv2Client({ region });\n\n try {\n const { ListEmailIdentitiesCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n\n const identities = await progress.execute(\n \"Loading domains from SES\",\n async () => {\n const response = await sesClient.send(\n new ListEmailIdentitiesCommand({})\n );\n return response.EmailIdentities || [];\n }\n );\n\n // Filter to only domains (not email addresses)\n const domains = identities.filter(\n (identity) =>\n identity.IdentityType === \"DOMAIN\" ||\n (identity.IdentityName && !identity.IdentityName.includes(\"@\"))\n );\n\n progress.stop();\n\n if (domains.length === 0) {\n clack.outro(\"No domains found in SES\");\n console.log(\n `\\nRun ${pc.cyan(\"wraps email domains add <domain>\")} to add a domain.\\n`\n );\n return;\n }\n\n // Get detailed info for each domain\n const domainDetails = await Promise.all(\n domains.map(async (domain) => {\n try {\n const details = await sesClient.send(\n new GetEmailIdentityCommand({\n EmailIdentity: domain.IdentityName!,\n })\n );\n return {\n name: domain.IdentityName!,\n verified: details.VerifiedForSendingStatus,\n dkimStatus: details.DkimAttributes?.Status || \"PENDING\",\n };\n } catch {\n return {\n name: domain.IdentityName!,\n verified: false,\n dkimStatus: \"UNKNOWN\",\n };\n }\n })\n );\n\n // Display domains in a formatted table\n const domainLines = domainDetails.map((domain) => {\n const statusIcon = domain.verified ? pc.green(\"✓\") : pc.yellow(\"⏱\");\n const dkimIcon =\n domain.dkimStatus === \"SUCCESS\" ? pc.green(\"✓\") : pc.yellow(\"⏱\");\n return ` ${statusIcon} ${pc.bold(domain.name)} DKIM: ${dkimIcon} ${domain.dkimStatus}`;\n });\n\n clack.note(\n domainLines.join(\"\\n\"),\n `${domains.length} domain(s) in ${region}`\n );\n clack.outro(\n pc.dim(\n `Run ${pc.cyan(\"wraps email domains verify --domain <domain>\")} for details`\n )\n );\n\n // Track list domains success\n trackCommand(\"email:domains:list\", {\n success: true,\n domain_count: domains.length,\n });\n } catch (error: any) {\n progress.stop();\n trackCommand(\"email:domains:list\", { success: false });\n throw error;\n }\n}\n\n/**\n * Get DKIM tokens for a domain\n */\nexport async function getDkim(options: { domain: string }): Promise<void> {\n clack.intro(pc.bold(`DKIM Tokens for ${options.domain}`));\n\n const progress = new DeploymentProgress();\n const region = await getAWSRegion();\n const sesClient = new SESv2Client({ region });\n\n try {\n const identity = await progress.execute(\n \"Fetching DKIM configuration\",\n async () => {\n const response = await sesClient.send(\n new GetEmailIdentityCommand({ EmailIdentity: options.domain })\n );\n return response;\n }\n );\n\n const dkimTokens = identity.DkimAttributes?.Tokens || [];\n const dkimStatus = identity.DkimAttributes?.Status || \"PENDING\";\n\n progress.stop();\n\n if (dkimTokens.length === 0) {\n clack.outro(pc.yellow(\"No DKIM tokens found for this domain\"));\n return;\n }\n\n // Display DKIM status\n const statusLine = `${pc.bold(\"DKIM Status:\")} ${\n dkimStatus === \"SUCCESS\"\n ? pc.green(\"✓ Verified\")\n : pc.yellow(`⏱ ${dkimStatus}`)\n }`;\n clack.note(statusLine, \"Status\");\n\n // Display DKIM records\n console.log(`\\n${pc.bold(\"DNS Records to add:\")}\\n`);\n for (const token of dkimTokens) {\n console.log(`${pc.cyan(`${token}._domainkey.${options.domain}`)}`);\n console.log(` ${pc.dim(\"Type:\")} CNAME`);\n console.log(` ${pc.dim(\"Value:\")} ${token}.dkim.amazonses.com\\n`);\n }\n\n if (dkimStatus !== \"SUCCESS\") {\n console.log(\n `${pc.dim(\"After adding these records, run:\")} ${pc.cyan(`wraps email domains verify --domain ${options.domain}`)}\\n`\n );\n }\n\n // Track get-dkim success\n trackCommand(\"email:domains:get-dkim\", {\n success: true,\n dkim_status: dkimStatus,\n });\n } catch (error: any) {\n progress.stop();\n trackCommand(\"email:domains:get-dkim\", { success: false });\n if (error.name === \"NotFoundException\") {\n clack.log.error(`Domain ${options.domain} not found in SES`);\n console.log(\n `\\nRun ${pc.cyan(`wraps email domains add ${options.domain}`)} to add this domain.\\n`\n );\n process.exit(1);\n return; // Return after process.exit for testing\n }\n throw error;\n }\n}\n\n/**\n * Remove a domain from SES\n */\nexport async function removeDomain(options: {\n domain: string;\n force?: boolean; // Destructive operation\n}): Promise<void> {\n clack.intro(pc.bold(`Remove domain ${options.domain} from SES`));\n\n const progress = new DeploymentProgress();\n const region = await getAWSRegion();\n const sesClient = new SESv2Client({ region });\n\n try {\n // Check if domain exists\n await progress.execute(\"Checking if domain exists\", async () => {\n await sesClient.send(\n new GetEmailIdentityCommand({ EmailIdentity: options.domain })\n );\n });\n\n progress.stop();\n\n // Confirm deletion\n if (!options.force) {\n const shouldContinue = await clack.confirm({\n message: `Are you sure you want to remove ${pc.red(options.domain)} from SES?`,\n initialValue: false,\n });\n\n if (clack.isCancel(shouldContinue) || !shouldContinue) {\n clack.cancel(\"Operation cancelled\");\n process.exit(0);\n }\n }\n\n // Delete the identity\n const { DeleteEmailIdentityCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n await progress.execute(\"Removing domain from SES\", async () => {\n await sesClient.send(\n new DeleteEmailIdentityCommand({\n EmailIdentity: options.domain,\n })\n );\n });\n\n progress.stop();\n clack.outro(pc.green(`✓ Domain ${options.domain} removed successfully`));\n\n // Track remove domain success\n trackCommand(\"email:domains:remove\", {\n success: true,\n });\n trackFeature(\"domain_removed\", {});\n } catch (error: any) {\n progress.stop();\n trackCommand(\"email:domains:remove\", { success: false });\n if (error.name === \"NotFoundException\") {\n clack.log.error(`Domain ${options.domain} not found in SES`);\n process.exit(1);\n return; // Return after process.exit for testing\n }\n throw error;\n }\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { deployEmailStack } from \"../../infrastructure/email-stack.js\";\nimport {\n trackError,\n trackServiceDeployed,\n trackServiceInit,\n} from \"../../telemetry/events.js\";\nimport type {\n EmailStackConfig,\n InitOptions,\n WrapsEmailConfig,\n} from \"../../types/index.js\";\nimport { getCostSummary } from \"../../utils/email/costs.js\";\nimport { getPreset, validateConfig } from \"../../utils/email/presets.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { errors } from \"../../utils/shared/errors.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n createConnectionMetadata,\n loadConnectionMetadata,\n saveConnectionMetadata,\n} from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayPreview,\n displaySuccess,\n} from \"../../utils/shared/output.js\";\nimport {\n confirmDeploy,\n promptConfigPreset,\n promptCustomConfig,\n promptDomain,\n promptEstimatedVolume,\n promptProvider,\n promptRegion,\n promptVercelConfig,\n} from \"../../utils/shared/prompts.js\";\nimport { ensurePulumiInstalled } from \"../../utils/shared/pulumi.js\";\n\n/**\n * Init command - Deploy new email infrastructure\n */\nexport async function init(options: InitOptions): Promise<void> {\n const startTime = Date.now();\n\n clack.intro(\n pc.bold(\n options.preview\n ? \"Wraps Email Infrastructure Preview\"\n : \"Wraps Email Infrastructure Setup\"\n )\n );\n\n const progress = new DeploymentProgress();\n\n // 1. Check Pulumi CLI is installed (auto-install if missing)\n const wasAutoInstalled = await progress.execute(\n \"Checking Pulumi CLI installation\",\n async () => await ensurePulumiInstalled()\n );\n\n if (wasAutoInstalled) {\n progress.info(\"Pulumi CLI was automatically installed\");\n }\n\n // 2. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`Connected to AWS account: ${pc.cyan(identity.accountId)}`);\n\n // 3. Get configuration (from options or prompts)\n let provider = options.provider;\n if (!provider) {\n provider = await promptProvider();\n }\n\n let region = options.region;\n if (!region) {\n const defaultRegion = await getAWSRegion();\n region = await promptRegion(defaultRegion);\n }\n\n let domain = options.domain;\n if (!domain) {\n domain = await promptDomain();\n }\n\n // Get Vercel config if needed\n let vercelConfig;\n if (provider === \"vercel\") {\n vercelConfig = await promptVercelConfig();\n }\n\n // 4. Check if connection already exists\n const existingConnection = await loadConnectionMetadata(\n identity.accountId,\n region\n );\n if (existingConnection) {\n clack.log.warn(\n `Connection already exists for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n clack.log.info(`Created: ${existingConnection.timestamp}`);\n clack.log.info(`Use ${pc.cyan(\"wraps status\")} to view current setup`);\n clack.log.info(`Use ${pc.cyan(\"wraps upgrade\")} to add more features`);\n process.exit(0);\n }\n\n // 5. Configuration selection\n let preset = options.preset;\n if (!preset) {\n preset = await promptConfigPreset();\n }\n\n let emailConfig: WrapsEmailConfig;\n if (preset === \"custom\") {\n emailConfig = await promptCustomConfig();\n } else {\n emailConfig = getPreset(preset)!;\n\n // Prompt for email archiving (optional feature for presets)\n const { promptEmailArchiving } = await import(\n \"../../utils/shared/prompts.js\"\n );\n const archivingConfig = await promptEmailArchiving();\n emailConfig.emailArchiving = archivingConfig;\n }\n\n // Set domain if provided\n if (domain) {\n emailConfig.domain = domain;\n }\n\n // Get estimated volume for cost calculation\n const estimatedVolume = await promptEstimatedVolume();\n\n // Display cost summary\n progress.info(`\\n${pc.bold(\"Cost Estimate:\")}`);\n const costSummary = getCostSummary(emailConfig, estimatedVolume);\n clack.log.info(costSummary);\n\n // Validate configuration and show warnings\n const warnings = validateConfig(emailConfig);\n if (warnings.length > 0) {\n progress.info(`\\n${pc.yellow(pc.bold(\"Configuration Warnings:\"))}`);\n for (const warning of warnings) {\n clack.log.warn(warning);\n }\n }\n\n // 6. Create metadata to track deployment\n const metadata = createConnectionMetadata(\n identity.accountId,\n region,\n provider,\n emailConfig,\n preset === \"custom\" ? undefined : preset\n );\n if (vercelConfig) {\n metadata.vercel = vercelConfig;\n }\n\n // Confirm deployment (skip if --yes flag or --preview flag)\n if (!(options.yes || options.preview)) {\n const confirmed = await confirmDeploy();\n if (!confirmed) {\n clack.cancel(\"Deployment cancelled.\");\n process.exit(0);\n }\n }\n\n // 7. Build stack configuration\n const stackConfig: EmailStackConfig = {\n provider,\n region,\n vercel: vercelConfig,\n emailConfig,\n };\n\n // 8. Preview or Deploy infrastructure using Pulumi\n if (options.preview) {\n // PREVIEW MODE - show what would be created without deploying\n try {\n const previewResult = await progress.execute(\n \"Generating infrastructure preview\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName: `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n mailFromDomain: result.mailFromDomain,\n archiveArn: result.archiveArn,\n archivingEnabled: result.archivingEnabled,\n archiveRetention: result.archiveRetention,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Run preview instead of deployment\n const result = await stack.preview({ diff: true });\n return result;\n }\n );\n\n // Display preview results\n displayPreview({\n changeSummary: previewResult.changeSummary,\n costEstimate: costSummary,\n commandName: \"wraps email init\",\n });\n\n clack.outro(\n pc.green(\"Preview complete. Run without --preview to deploy.\")\n );\n\n // Track preview completion\n trackServiceInit(\"email\", true, {\n preset,\n provider,\n region,\n preview: true,\n duration_ms: Date.now() - startTime,\n });\n return;\n } catch (error: any) {\n trackError(\"PREVIEW_FAILED\", \"email:init\", { step: \"preview\" });\n if (error.message?.includes(\"stack is currently locked\")) {\n throw errors.stackLocked();\n }\n throw new Error(`Preview failed: ${error.message}`);\n }\n }\n\n // DEPLOY MODE - actually create infrastructure\n let outputs;\n try {\n outputs = await progress.execute(\n \"Deploying infrastructure (this may take 2-3 minutes)\",\n async () => {\n // Ensure Pulumi workspace directory exists\n await ensurePulumiWorkDir();\n\n // Run Pulumi inline program with local backend (no cloud required)\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName: `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n\n // Export outputs\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n mailFromDomain: result.mailFromDomain,\n archiveArn: result.archiveArn,\n archivingEnabled: result.archivingEnabled,\n archiveRetention: result.archiveRetention,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n // Use local file-based backend (no Pulumi Cloud login required)\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\", // Use empty passphrase for local state\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n // Set backend to local file system\n await stack.workspace.selectStack(\n `wraps-${identity.accountId}-${region}`\n );\n\n // Set AWS region\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Run the deployment\n const upResult = await stack.up({ onOutput: () => {} }); // Suppress Pulumi output\n\n // Get outputs\n const pulumiOutputs = upResult.outputs;\n\n return {\n roleArn: pulumiOutputs.roleArn?.value as string,\n configSetName: pulumiOutputs.configSetName?.value as\n | string\n | undefined,\n tableName: pulumiOutputs.tableName?.value as string | undefined,\n region: pulumiOutputs.region?.value as string,\n lambdaFunctions: pulumiOutputs.lambdaFunctions?.value as\n | string[]\n | undefined,\n domain: pulumiOutputs.domain?.value as string | undefined,\n dkimTokens: pulumiOutputs.dkimTokens?.value as string[] | undefined,\n customTrackingDomain: pulumiOutputs.customTrackingDomain?.value as\n | string\n | undefined,\n mailFromDomain: pulumiOutputs.mailFromDomain?.value as\n | string\n | undefined,\n archiveArn: pulumiOutputs.archiveArn?.value as string | undefined,\n archivingEnabled: pulumiOutputs.archivingEnabled?.value as\n | boolean\n | undefined,\n archiveRetention: pulumiOutputs.archiveRetention?.value as\n | string\n | undefined,\n };\n }\n );\n } catch (error: any) {\n // Track deployment failure\n trackServiceInit(\"email\", false, {\n preset,\n provider,\n region,\n duration_ms: Date.now() - startTime,\n });\n\n // Check if it's a lock file error\n if (error.message?.includes(\"stack is currently locked\")) {\n trackError(\"STACK_LOCKED\", \"email:init\", { step: \"deploy\" });\n throw errors.stackLocked();\n }\n\n trackError(\"DEPLOYMENT_FAILED\", \"email:init\", { step: \"deploy\" });\n throw new Error(`Pulumi deployment failed: ${error.message}`);\n }\n\n // 9. Save metadata for future upgrades and restore\n if (metadata.services.email) {\n metadata.services.email.pulumiStackName = `wraps-${identity.accountId}-${region}`;\n // Save computed values from Pulumi outputs back to config\n // These may have been computed during deployment (e.g., mailFromDomain from mailFromSubdomain)\n if (outputs.mailFromDomain) {\n metadata.services.email.config.mailFromDomain = outputs.mailFromDomain;\n }\n if (\n outputs.customTrackingDomain &&\n metadata.services.email.config.tracking\n ) {\n metadata.services.email.config.tracking.customRedirectDomain =\n outputs.customTrackingDomain;\n }\n }\n await saveConnectionMetadata(metadata);\n\n progress.info(\"Connection metadata saved for upgrade and restore capability\");\n\n // 10. Check if Route53 hosted zone exists and offer to create DNS records\n let dnsAutoCreated = false;\n if (outputs.domain && outputs.dkimTokens && outputs.dkimTokens.length > 0) {\n const {\n findHostedZone,\n previewDNSChanges,\n createSelectedDNSRecords,\n } = await import(\"../../utils/route53.js\");\n const { promptDNSManagement, promptDNSConfirmation } = await import(\n \"../../utils/shared/prompts.js\"\n );\n const hostedZone = await findHostedZone(outputs.domain, region);\n\n if (hostedZone) {\n // Ask if user wants to manage DNS via Route53\n const manageDNS = await promptDNSManagement(outputs.domain);\n\n if (manageDNS) {\n try {\n // Preview DNS changes and show conflicts\n progress.start(\"Checking existing DNS records\");\n const dnsPreview = await previewDNSChanges(\n hostedZone.id,\n outputs.domain,\n outputs.dkimTokens,\n region,\n outputs.customTrackingDomain,\n outputs.mailFromDomain\n );\n progress.stop();\n\n // Show preview and get user confirmation\n const { shouldCreate, selectedCategories } =\n await promptDNSConfirmation(dnsPreview);\n\n if (shouldCreate && selectedCategories.size > 0) {\n progress.start(\"Creating selected DNS records in Route53\");\n await createSelectedDNSRecords(\n hostedZone.id,\n outputs.domain,\n outputs.dkimTokens,\n region,\n selectedCategories as Set<any>,\n outputs.customTrackingDomain,\n outputs.mailFromDomain\n );\n progress.succeed(\n `Created ${selectedCategories.size} DNS record group(s) in Route53`\n );\n dnsAutoCreated = true;\n } else {\n clack.log.info(\"Skipping DNS record creation. You can add them manually.\");\n }\n } catch (error: any) {\n progress.stop();\n clack.log.warn(`Could not manage DNS records: ${error.message}`);\n }\n }\n }\n }\n\n // 11. Format DNS records if domain was provided and DNS wasn't auto-created\n const dnsRecords = [];\n if (\n outputs.domain &&\n outputs.dkimTokens &&\n outputs.dkimTokens.length > 0 &&\n !dnsAutoCreated\n ) {\n // Add DKIM CNAME records\n for (const token of outputs.dkimTokens) {\n dnsRecords.push({\n name: `${token}._domainkey.${outputs.domain}`,\n type: \"CNAME\",\n value: `${token}.dkim.amazonses.com`,\n });\n }\n }\n\n // 12. Display success message\n displaySuccess({\n roleArn: outputs.roleArn,\n configSetName: outputs.configSetName,\n region: outputs.region!,\n tableName: outputs.tableName,\n dnsRecords: dnsRecords.length > 0 ? dnsRecords : undefined,\n dnsAutoCreated,\n domain: outputs.domain,\n mailFromDomain: outputs.mailFromDomain,\n });\n\n // 13. Track successful deployment\n const duration = Date.now() - startTime;\n const enabledFeatures: string[] = [];\n if (emailConfig.tracking?.enabled) enabledFeatures.push(\"tracking\");\n if (emailConfig.suppressionList?.enabled)\n enabledFeatures.push(\"suppression_list\");\n if (emailConfig.eventTracking?.enabled)\n enabledFeatures.push(\"event_tracking\");\n if (emailConfig.eventTracking?.dynamoDBHistory)\n enabledFeatures.push(\"dynamodb_history\");\n if (emailConfig.dedicatedIp) enabledFeatures.push(\"dedicated_ip\");\n if (emailConfig.emailArchiving?.enabled)\n enabledFeatures.push(\"email_archiving\");\n\n trackServiceInit(\"email\", true, {\n preset,\n provider,\n region,\n features: enabledFeatures,\n duration_ms: duration,\n });\n\n trackServiceDeployed(\"email\", {\n duration_ms: duration,\n region,\n features: enabledFeatures,\n preset,\n });\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { trackError, trackServiceRemoved } from \"../../telemetry/events.js\";\nimport type { EmailRestoreOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { getPulumiWorkDir } from \"../../utils/shared/fs.js\";\nimport {\n deleteConnectionMetadata,\n loadConnectionMetadata,\n} from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayPreview,\n} from \"../../utils/shared/output.js\";\n\n/**\n * Restore command - Remove Wraps infrastructure (alias for destroy)\n *\n * Note: This command removes all Wraps-managed resources.\n * Since Wraps always creates NEW resources (wraps- prefix) and never modifies\n * existing infrastructure, there's nothing to \"restore\" - only to remove.\n */\nexport async function restore(options: EmailRestoreOptions): Promise<void> {\n const startTime = Date.now();\n\n clack.intro(\n pc.bold(\n options.preview\n ? \"Wraps Restore Preview\"\n : \"Wraps Restore - Remove Wraps Infrastructure\"\n )\n );\n\n clack.log.info(\n `${pc.yellow(\"Note:\")} This will remove all Wraps-managed infrastructure.`\n );\n clack.log.info(\n \"Your original AWS resources remain untouched (Wraps never modifies them).\\n\"\n );\n\n const progress = new DeploymentProgress();\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`Connected to AWS account: ${pc.cyan(identity.accountId)}`);\n\n // 2. Get region\n let region = options.region;\n if (!region) {\n const defaultRegion = await getAWSRegion();\n region = defaultRegion;\n }\n\n // 3. Load connection metadata\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n\n if (!metadata) {\n clack.log.error(\n `No Wraps connection found for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} or ${pc.cyan(\"wraps email connect\")} to create a connection first.`\n );\n process.exit(1);\n }\n\n progress.info(`Found connection created: ${metadata.timestamp}`);\n\n // 4. Display what will be removed\n console.log(\n `\\n${pc.bold(\"The following Wraps resources will be removed:\")}\\n`\n );\n\n if (metadata.services.email?.config.tracking?.enabled) {\n console.log(` ${pc.cyan(\"✓\")} Configuration Set (wraps-email-tracking)`);\n }\n if (metadata.services.email?.config.eventTracking?.dynamoDBHistory) {\n console.log(` ${pc.cyan(\"✓\")} DynamoDB Table (wraps-email-history)`);\n }\n if (metadata.services.email?.config.eventTracking?.enabled) {\n console.log(` ${pc.cyan(\"✓\")} EventBridge Rules`);\n console.log(` ${pc.cyan(\"✓\")} SQS Queues`);\n console.log(` ${pc.cyan(\"✓\")} Lambda Functions`);\n }\n console.log(` ${pc.cyan(\"✓\")} IAM Role (wraps-email-role)`);\n console.log(\"\");\n\n // 5. Confirm removal (skip if --force or --preview)\n if (!(options.force || options.preview)) {\n const confirmed = await clack.confirm({\n message: \"Proceed with removal? This cannot be undone.\",\n initialValue: false,\n });\n\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel(\"Removal cancelled.\");\n process.exit(0);\n }\n }\n\n // 6. Preview or Destroy Pulumi stack\n if (options.preview) {\n // PREVIEW MODE - show what would be destroyed without actually destroying\n if (metadata.services.email?.pulumiStackName) {\n try {\n const previewResult = await progress.execute(\n \"Generating removal preview\",\n async () => {\n const stack = await pulumi.automation.LocalWorkspace.selectStack(\n {\n stackName: metadata.services.email!.pulumiStackName!,\n projectName: \"wraps-email\",\n program: async () => {}, // Empty program for destroy\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n // Run preview to see what would be destroyed\n const result = await stack.preview({ diff: true });\n return result;\n }\n );\n\n // Display preview results\n displayPreview({\n changeSummary: previewResult.changeSummary,\n costEstimate: \"Monthly cost after removal: $0.00\",\n commandName: \"wraps email restore\",\n });\n\n clack.outro(\n pc.green(\n \"Preview complete. Run without --preview to remove infrastructure.\"\n )\n );\n\n // Track preview completion\n trackServiceRemoved(\"email\", {\n preview: true,\n duration_ms: Date.now() - startTime,\n });\n return;\n } catch (error: any) {\n trackError(\"PREVIEW_FAILED\", \"email:restore\", { step: \"preview\" });\n throw new Error(`Preview failed: ${error.message}`);\n }\n }\n return;\n }\n\n // DESTROY MODE - actually remove infrastructure\n if (metadata.services.email?.pulumiStackName) {\n await progress.execute(\"Removing Wraps infrastructure\", async () => {\n try {\n if (!metadata.services.email?.pulumiStackName) {\n throw new Error(\"No Pulumi stack name found in metadata\");\n }\n\n const stack = await pulumi.automation.LocalWorkspace.selectStack(\n {\n stackName: metadata.services.email.pulumiStackName,\n projectName: \"wraps-email\",\n program: async () => {}, // Empty program\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n // Destroy the stack\n await stack.destroy({ onOutput: () => {} });\n\n // Remove the stack\n await stack.workspace.removeStack(\n metadata.services.email.pulumiStackName\n );\n } catch (error: any) {\n trackError(\"DESTROY_FAILED\", \"email:restore\", { step: \"destroy\" });\n throw new Error(`Failed to destroy Pulumi stack: ${error.message}`);\n }\n });\n }\n\n // 7. Delete connection metadata\n await deleteConnectionMetadata(identity.accountId, region);\n\n progress.info(\"Connection metadata deleted\");\n\n // 8. Success message\n console.log(\n `\\n${pc.green(\"✓\")} ${pc.bold(\"Infrastructure removed successfully!\")}\\n`\n );\n console.log(\n `${pc.dim(\"All Wraps resources have been deleted from your AWS account.\")}`\n );\n console.log(`${pc.dim(\"Your original AWS resources remain unchanged.\")}\\n`);\n\n // 9. Track successful removal\n trackServiceRemoved(\"email\", {\n reason: \"user_initiated\",\n duration_ms: Date.now() - startTime,\n });\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { trackCommand } from \"../../telemetry/events.js\";\nimport type { StatusOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n listSESDomains,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport { findConnectionsWithService } from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayStatus,\n} from \"../../utils/shared/output.js\";\n\n/**\n * Email Status command - Show current email infrastructure setup\n */\nexport async function emailStatus(options: StatusOptions): Promise<void> {\n const startTime = Date.now();\n const progress = new DeploymentProgress();\n\n clack.intro(pc.bold(\"Wraps Email Status\"));\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Loading email infrastructure status\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region - check flag, then env, then metadata, then default\n let region = options.region || (await getAWSRegion());\n\n // If using default region (us-east-1), check if we have metadata for other regions\n if (\n !(\n options.region ||\n process.env.AWS_REGION ||\n process.env.AWS_DEFAULT_REGION\n )\n ) {\n const emailConnections = await findConnectionsWithService(\n identity.accountId,\n \"email\"\n );\n\n if (emailConnections.length === 1) {\n // Auto-select the only available region\n region = emailConnections[0].region;\n } else if (emailConnections.length > 1) {\n // Multiple regions found - prompt user to select\n const selectedRegion = await clack.select({\n message: \"Multiple email deployments found. Which region?\",\n options: emailConnections.map((conn) => ({\n value: conn.region,\n label: conn.region,\n })),\n });\n\n if (clack.isCancel(selectedRegion)) {\n clack.cancel(\"Operation cancelled\");\n process.exit(0);\n }\n\n region = selectedRegion as string;\n }\n }\n\n // 3. Try to load Pulumi stack\n let stackOutputs: any = {};\n try {\n // Ensure Pulumi workspace is configured (sets backend URL)\n await ensurePulumiWorkDir();\n\n const stack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName: `wraps-${identity.accountId}-${region}`,\n workDir: getPulumiWorkDir(),\n });\n\n stackOutputs = await stack.outputs();\n } catch (_error: any) {\n progress.stop();\n clack.log.error(\"No email infrastructure found\");\n console.log(\n `\\nRun ${pc.cyan(\"wraps email init\")} to deploy email infrastructure.\\n`\n );\n process.exit(1);\n }\n\n // 4. Get SES domains with DKIM tokens\n const domains = await listSESDomains(region);\n\n // 4a. Fetch DKIM tokens for each domain\n const { SESv2Client, GetEmailIdentityCommand } = await import(\n \"@aws-sdk/client-sesv2\"\n );\n const sesv2Client = new SESv2Client({ region });\n\n const domainsWithTokens = await Promise.all(\n domains.map(async (d) => {\n try {\n const identity = await sesv2Client.send(\n new GetEmailIdentityCommand({ EmailIdentity: d.domain })\n );\n return {\n domain: d.domain,\n status: d.verified ? (\"verified\" as const) : (\"pending\" as const),\n dkimTokens: identity.DkimAttributes?.Tokens || [],\n mailFromDomain: identity.MailFromAttributes?.MailFromDomain,\n mailFromStatus: identity.MailFromAttributes?.MailFromDomainStatus,\n };\n } catch (_error) {\n return {\n domain: d.domain,\n status: d.verified ? (\"verified\" as const) : (\"pending\" as const),\n dkimTokens: undefined,\n mailFromDomain: undefined,\n mailFromStatus: undefined,\n };\n }\n })\n );\n\n // 5. Determine integration level\n const integrationLevel = stackOutputs.configSetName\n ? \"enhanced\"\n : \"dashboard-only\";\n\n // 6. Display status\n progress.stop();\n displayStatus({\n integrationLevel: integrationLevel as \"dashboard-only\" | \"enhanced\",\n region,\n domains: domainsWithTokens,\n resources: {\n roleArn: stackOutputs.roleArn?.value,\n configSetName: stackOutputs.configSetName?.value,\n tableName: stackOutputs.tableName?.value,\n lambdaFunctions: stackOutputs.lambdaFunctions?.value?.length || 0,\n snsTopics: integrationLevel === \"enhanced\" ? 1 : 0,\n archiveArn: stackOutputs.archiveArn?.value,\n archivingEnabled: stackOutputs.archivingEnabled?.value,\n archiveRetention: stackOutputs.archiveRetention?.value,\n },\n tracking: stackOutputs.customTrackingDomain?.value\n ? {\n customTrackingDomain: stackOutputs.customTrackingDomain?.value,\n httpsEnabled: stackOutputs.httpsTrackingEnabled?.value,\n cloudFrontDomain: stackOutputs.cloudFrontDomain?.value,\n }\n : undefined,\n });\n\n // 7. Track status command\n trackCommand(\"email:status\", {\n success: true,\n region,\n domain_count: domainsWithTokens.length,\n integration_level: integrationLevel,\n duration_ms: Date.now() - startTime,\n });\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { deployEmailStack } from \"../../infrastructure/email-stack.js\";\nimport { trackError, trackServiceUpgrade } from \"../../telemetry/events.js\";\nimport type {\n EmailStackConfig,\n UpgradeOptions,\n WrapsEmailConfig,\n} from \"../../types/index.js\";\nimport { calculateCosts, formatCost } from \"../../utils/email/costs.js\";\nimport { getAllPresetInfo, getPreset } from \"../../utils/email/presets.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { errors } from \"../../utils/shared/errors.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n applyConfigUpdates,\n loadConnectionMetadata,\n saveConnectionMetadata,\n updateEmailConfig,\n} from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayPreview,\n displaySuccess,\n} from \"../../utils/shared/output.js\";\nimport { promptVercelConfig } from \"../../utils/shared/prompts.js\";\nimport { ensurePulumiInstalled } from \"../../utils/shared/pulumi.js\";\n\n/**\n * Upgrade command - Enhance existing Wraps infrastructure\n */\nexport async function upgrade(options: UpgradeOptions): Promise<void> {\n const startTime = Date.now();\n let upgradeAction: string | symbol = \"\";\n\n clack.intro(\n pc.bold(\n options.preview\n ? \"Wraps Upgrade Preview\"\n : \"Wraps Upgrade - Enhance Your Email Infrastructure\"\n )\n );\n\n const progress = new DeploymentProgress();\n\n // 1. Check Pulumi CLI is installed\n const wasAutoInstalled = await progress.execute(\n \"Checking Pulumi CLI installation\",\n async () => await ensurePulumiInstalled()\n );\n\n if (wasAutoInstalled) {\n progress.info(\"Pulumi CLI was automatically installed\");\n }\n\n // 2. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`Connected to AWS account: ${pc.cyan(identity.accountId)}`);\n\n // 3. Get region\n let region = options.region;\n if (!region) {\n const defaultRegion = await getAWSRegion();\n region = defaultRegion;\n }\n\n // 4. Load existing connection metadata\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n\n if (!metadata) {\n clack.log.error(\n `No Wraps connection found for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} to create new infrastructure or ${pc.cyan(\"wraps email connect\")} to connect existing.`\n );\n process.exit(1);\n }\n\n progress.info(`Found existing connection created: ${metadata.timestamp}`);\n\n // 5. Display current configuration\n console.log(`\\n${pc.bold(\"Current Configuration:\")}\\n`);\n\n if (metadata.services.email?.preset) {\n console.log(` Preset: ${pc.cyan(metadata.services.email?.preset)}`);\n } else {\n console.log(` Preset: ${pc.cyan(\"custom\")}`);\n }\n\n const config = metadata.services.email?.config;\n\n if (!config) {\n clack.log.error(\"No email configuration found in metadata\");\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} to create new infrastructure.`\n );\n process.exit(1);\n }\n\n // Show sending domain if configured\n if (config.domain) {\n console.log(` Sending Domain: ${pc.cyan(config.domain)}`);\n }\n\n if (config.tracking?.enabled) {\n console.log(` ${pc.green(\"✓\")} Open & Click Tracking`);\n if (config.tracking.customRedirectDomain) {\n console.log(\n ` ${pc.dim(\"└─\")} Custom domain: ${pc.cyan(config.tracking.customRedirectDomain)}`\n );\n }\n }\n\n if (config.suppressionList?.enabled) {\n console.log(` ${pc.green(\"✓\")} Bounce/Complaint Suppression`);\n }\n\n if (config.eventTracking?.enabled) {\n console.log(` ${pc.green(\"✓\")} Event Tracking (EventBridge)`);\n if (config.eventTracking.dynamoDBHistory) {\n console.log(\n ` ${pc.dim(\"└─\")} Email History: ${pc.cyan(config.eventTracking.archiveRetention || \"90days\")}`\n );\n }\n }\n\n if (config.dedicatedIp) {\n console.log(` ${pc.green(\"✓\")} Dedicated IP Address`);\n }\n\n if (config.emailArchiving?.enabled) {\n const retentionLabel =\n {\n \"7days\": \"7 days\",\n \"30days\": \"30 days\",\n \"90days\": \"90 days\",\n \"3months\": \"3 months\",\n \"6months\": \"6 months\",\n \"9months\": \"9 months\",\n \"1year\": \"1 year\",\n \"18months\": \"18 months\",\n \"2years\": \"2 years\",\n \"30months\": \"30 months\",\n \"3years\": \"3 years\",\n \"4years\": \"4 years\",\n \"5years\": \"5 years\",\n \"6years\": \"6 years\",\n \"7years\": \"7 years\",\n \"8years\": \"8 years\",\n \"9years\": \"9 years\",\n \"10years\": \"10 years\",\n indefinite: \"indefinite\",\n permanent: \"permanent\",\n }[config.emailArchiving.retention] || \"90 days\";\n console.log(` ${pc.green(\"✓\")} Email Archiving (${retentionLabel})`);\n }\n\n // Calculate current cost\n const currentCostData = calculateCosts(config, 50_000); // Assume 50k emails/mo for estimate\n console.log(\n `\\n Estimated Cost: ${pc.cyan(`~${formatCost(currentCostData.total.monthly)}/mo`)}`\n );\n\n console.log(\"\");\n\n // 6. Prompt for upgrade action\n upgradeAction = await clack.select({\n message: \"What would you like to do?\",\n options: [\n {\n value: \"preset\",\n label: \"Upgrade to a different preset\",\n hint: \"Starter → Production → Enterprise\",\n },\n {\n value: \"archiving\",\n label: config.emailArchiving?.enabled\n ? \"Change email archiving settings\"\n : \"Enable email archiving\",\n hint: config.emailArchiving?.enabled\n ? \"Update retention or disable\"\n : \"Store full email content with HTML\",\n },\n {\n value: \"tracking-domain\",\n label: \"Add/change custom tracking domain\",\n hint: \"Use your own domain for email links\",\n },\n {\n value: \"retention\",\n label: \"Change email history retention\",\n hint: \"7 days, 30 days, 90 days, 6 months, 1 year, 18 months\",\n },\n {\n value: \"events\",\n label: \"Customize tracked event types\",\n hint: \"Choose which SES events to track\",\n },\n {\n value: \"dedicated-ip\",\n label: \"Enable dedicated IP address\",\n hint: \"Requires 100k+ emails/day ($50-100/mo)\",\n },\n {\n value: \"custom\",\n label: \"Custom configuration\",\n hint: \"Modify multiple settings at once\",\n },\n ],\n });\n\n if (clack.isCancel(upgradeAction)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n let updatedConfig: WrapsEmailConfig = { ...config };\n let newPreset: string | undefined = metadata.services.email?.preset;\n\n // 7. Handle upgrade action\n switch (upgradeAction) {\n case \"preset\": {\n // Show available presets\n const presets = getAllPresetInfo();\n const currentPresetIdx = presets.findIndex(\n (p) => p.name.toLowerCase() === metadata.services.email?.preset\n );\n\n const availablePresets = presets\n .map((p, idx) => ({\n value: p.name.toLowerCase(),\n label: `${p.name} - ${p.description}`,\n hint: `${p.volume} | Est. ${p.estimatedCost}/mo`,\n disabled:\n currentPresetIdx >= 0 && idx <= currentPresetIdx\n ? \"Current or lower tier\"\n : undefined,\n }))\n .filter((p) => !p.disabled);\n\n if (availablePresets.length === 0) {\n clack.log.warn(\"Already on highest preset (Enterprise)\");\n process.exit(0);\n }\n\n const selectedPreset = await clack.select({\n message: \"Select new preset:\",\n options: availablePresets,\n });\n\n if (clack.isCancel(selectedPreset)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n // Get preset config but preserve user-customized fields from existing config\n const presetConfig = getPreset(selectedPreset as any)!;\n\n // Apply preset updates to existing config (preserves user customizations)\n updatedConfig = applyConfigUpdates(config, presetConfig);\n newPreset = selectedPreset as string;\n break;\n }\n\n case \"archiving\": {\n if (config.emailArchiving?.enabled) {\n // Already enabled - allow changing retention or disabling\n const archivingAction = await clack.select({\n message: \"What would you like to do with email archiving?\",\n options: [\n {\n value: \"change-retention\",\n label: \"Change retention period\",\n hint: `Current: ${config.emailArchiving.retention}`,\n },\n {\n value: \"disable\",\n label: \"Disable email archiving\",\n hint: \"Stop storing full email content\",\n },\n ],\n });\n\n if (clack.isCancel(archivingAction)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n if (archivingAction === \"disable\") {\n const confirmDisable = await clack.confirm({\n message:\n \"Are you sure? Existing archived emails will remain, but new emails won't be archived.\",\n initialValue: false,\n });\n\n if (clack.isCancel(confirmDisable) || !confirmDisable) {\n clack.cancel(\"Archiving not disabled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n emailArchiving: {\n enabled: false,\n retention: config.emailArchiving.retention,\n },\n };\n } else {\n // Change retention\n const retention = await clack.select({\n message: \"Email archive retention period:\",\n options: [\n {\n value: \"7days\",\n label: \"7 days\",\n hint: \"~$1-2/mo for 10k emails\",\n },\n {\n value: \"30days\",\n label: \"30 days\",\n hint: \"~$2-4/mo for 10k emails\",\n },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"~$5-10/mo for 10k emails\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"~$15-25/mo for 10k emails\",\n },\n {\n value: \"1year\",\n label: \"1 year\",\n hint: \"~$25-40/mo for 10k emails\",\n },\n {\n value: \"18months\",\n label: \"18 months\",\n hint: \"~$35-60/mo for 10k emails\",\n },\n ],\n initialValue: config.emailArchiving.retention,\n });\n\n if (clack.isCancel(retention)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n emailArchiving: {\n enabled: true,\n retention: retention as any,\n },\n };\n }\n } else {\n // Not enabled - prompt to enable with retention selection\n const enableArchiving = await clack.confirm({\n message:\n \"Enable email archiving? (Store full email content with HTML for viewing)\",\n initialValue: true,\n });\n\n if (clack.isCancel(enableArchiving)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n if (!enableArchiving) {\n clack.log.info(\"Email archiving not enabled.\");\n process.exit(0);\n }\n\n const retention = await clack.select({\n message: \"Email archive retention period:\",\n options: [\n {\n value: \"7days\",\n label: \"7 days\",\n hint: \"~$1-2/mo for 10k emails\",\n },\n {\n value: \"30days\",\n label: \"30 days\",\n hint: \"~$2-4/mo for 10k emails\",\n },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"~$5-10/mo for 10k emails\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"~$15-25/mo for 10k emails\",\n },\n {\n value: \"1year\",\n label: \"1 year\",\n hint: \"~$25-40/mo for 10k emails\",\n },\n {\n value: \"18months\",\n label: \"18 months\",\n hint: \"~$35-60/mo for 10k emails\",\n },\n ],\n initialValue: \"90days\",\n });\n\n if (clack.isCancel(retention)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n clack.log.info(\n pc.dim(\n \"Archiving stores full RFC 822 emails with HTML, attachments, and headers\"\n )\n );\n clack.log.info(\n pc.dim(\n \"Cost: $2/GB ingestion + $0.19/GB/month storage (~50KB per email)\"\n )\n );\n\n updatedConfig = {\n ...config,\n emailArchiving: {\n enabled: true,\n retention: retention as any,\n },\n };\n }\n newPreset = undefined; // Custom config\n break;\n }\n\n case \"tracking-domain\": {\n // First, check if a sending identity (domain) is configured and verified\n if (!config.domain) {\n clack.log.error(\n \"No sending domain configured. You must configure a sending domain before adding a custom tracking domain.\"\n );\n clack.log.info(\n `Use ${pc.cyan(\"wraps email init\")} to set up a sending domain first.`\n );\n process.exit(1);\n }\n\n // Verify that the sending identity is verified\n const { listSESDomains } = await import(\"../../utils/shared/aws.js\");\n const domains = await progress.execute(\n \"Checking domain verification status\",\n async () => await listSESDomains(region)\n );\n\n const sendingDomain = domains.find((d) => d.domain === config.domain);\n\n if (!sendingDomain?.verified) {\n clack.log.error(\n `Sending domain ${pc.cyan(config.domain)} is not verified.`\n );\n clack.log.info(\n \"You must verify your sending domain before adding a custom tracking domain.\"\n );\n clack.log.info(\n `Use ${pc.cyan(\"wraps email verify\")} to check DNS records and complete verification.`\n );\n process.exit(1);\n }\n\n progress.info(\n `Sending domain ${pc.cyan(config.domain)} is verified ${pc.green(\"✓\")}`\n );\n\n const trackingDomain = await clack.text({\n message: \"Custom tracking redirect domain:\",\n placeholder: \"track.yourdomain.com\",\n initialValue: config.tracking?.customRedirectDomain || \"\",\n validate: (value) => {\n if (value && !/^[a-z0-9.-]+\\.[a-z]{2,}$/.test(value)) {\n return \"Please enter a valid domain\";\n }\n },\n });\n\n if (clack.isCancel(trackingDomain)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n // Ask if HTTPS tracking should be enabled\n const enableHttps = await clack.confirm({\n message: \"Enable HTTPS tracking with CloudFront + SSL certificate?\",\n initialValue: true,\n });\n\n if (clack.isCancel(enableHttps)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n if (enableHttps) {\n clack.log.info(\n pc.dim(\n \"HTTPS tracking creates a CloudFront distribution with an SSL certificate.\"\n )\n );\n clack.log.info(\n pc.dim(\n \"This ensures all tracking links use secure HTTPS connections.\"\n )\n );\n\n // Check if domain has Route53 hosted zone\n const { findHostedZone } = await import(\"../../utils/route53.js\");\n const hostedZone = await progress.execute(\n \"Checking for Route53 hosted zone\",\n async () =>\n await findHostedZone(trackingDomain || config.domain!, region)\n );\n\n if (hostedZone) {\n progress.info(\n `Found Route53 hosted zone: ${pc.cyan(hostedZone.name)} ${pc.green(\"✓\")}`\n );\n clack.log.info(\n pc.dim(\n \"DNS records (SSL certificate validation + CloudFront) will be created automatically.\"\n )\n );\n } else {\n clack.log.warn(\n `No Route53 hosted zone found for ${pc.cyan(trackingDomain || config.domain!)}`\n );\n clack.log.info(\n pc.dim(\n \"You'll need to manually create DNS records for SSL certificate validation and CloudFront.\"\n )\n );\n clack.log.info(\n pc.dim(\"DNS record details will be shown after deployment.\")\n );\n }\n\n const confirmHttps = await clack.confirm({\n message: hostedZone\n ? \"Proceed with automatic HTTPS setup?\"\n : \"Proceed with manual HTTPS setup (requires DNS configuration)?\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirmHttps) || !confirmHttps) {\n clack.log.info(\"HTTPS tracking not enabled. Using HTTP tracking.\");\n updatedConfig = {\n ...config,\n tracking: {\n ...config.tracking,\n enabled: true,\n customRedirectDomain: trackingDomain || undefined,\n httpsEnabled: false,\n },\n };\n } else {\n updatedConfig = {\n ...config,\n tracking: {\n ...config.tracking,\n enabled: true,\n customRedirectDomain: trackingDomain || undefined,\n httpsEnabled: true,\n },\n };\n }\n } else {\n clack.log.info(\n pc.dim(\n \"Using HTTP tracking (standard). Links will use http:// protocol.\"\n )\n );\n updatedConfig = {\n ...config,\n tracking: {\n ...config.tracking,\n enabled: true,\n customRedirectDomain: trackingDomain || undefined,\n httpsEnabled: false,\n },\n };\n }\n\n newPreset = undefined; // Custom config\n break;\n }\n\n case \"retention\": {\n const retention = await clack.select({\n message: \"Email history retention period (event data in DynamoDB):\",\n options: [\n { value: \"7days\", label: \"7 days\", hint: \"Minimal storage cost\" },\n { value: \"30days\", label: \"30 days\", hint: \"Development/testing\" },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"Standard retention\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"Extended retention\",\n },\n { value: \"1year\", label: \"1 year\", hint: \"Compliance requirements\" },\n {\n value: \"18months\",\n label: \"18 months\",\n hint: \"Long-term retention\",\n },\n ],\n initialValue: config.eventTracking?.archiveRetention || \"90days\",\n });\n\n if (clack.isCancel(retention)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n clack.log.info(\n pc.dim(\n \"Note: This is for event data (sent, delivered, opened, etc.) stored in DynamoDB.\"\n )\n );\n clack.log.info(\n pc.dim(\n \"For full email content storage, use 'Enable email archiving' option.\"\n )\n );\n\n updatedConfig = {\n ...config,\n eventTracking: {\n ...config.eventTracking,\n enabled: true,\n dynamoDBHistory: true,\n archiveRetention: retention as any,\n },\n };\n newPreset = undefined; // Custom config\n break;\n }\n\n case \"events\": {\n const selectedEvents = await clack.multiselect({\n message: \"Select SES event types to track:\",\n options: [\n { value: \"SEND\", label: \"Send\", hint: \"Email sent to SES\" },\n {\n value: \"DELIVERY\",\n label: \"Delivery\",\n hint: \"Email delivered successfully\",\n },\n { value: \"OPEN\", label: \"Open\", hint: \"Recipient opened email\" },\n { value: \"CLICK\", label: \"Click\", hint: \"Recipient clicked link\" },\n { value: \"BOUNCE\", label: \"Bounce\", hint: \"Email bounced\" },\n {\n value: \"COMPLAINT\",\n label: \"Complaint\",\n hint: \"Spam complaint received\",\n },\n { value: \"REJECT\", label: \"Reject\", hint: \"Email rejected by SES\" },\n {\n value: \"RENDERING_FAILURE\",\n label: \"Rendering Failure\",\n hint: \"Template rendering failed\",\n },\n {\n value: \"DELIVERY_DELAY\",\n label: \"Delivery Delay\",\n hint: \"Temporary delivery delay\",\n },\n {\n value: \"SUBSCRIPTION\",\n label: \"Subscription\",\n hint: \"List subscription event\",\n },\n ],\n initialValues: config.eventTracking?.events || [\n \"SEND\",\n \"DELIVERY\",\n \"OPEN\",\n \"CLICK\",\n \"BOUNCE\",\n \"COMPLAINT\",\n ],\n required: true,\n });\n\n if (clack.isCancel(selectedEvents)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n eventTracking: {\n ...config.eventTracking,\n enabled: true,\n events: selectedEvents as any,\n },\n };\n newPreset = undefined; // Custom config\n break;\n }\n\n case \"dedicated-ip\": {\n const confirmed = await clack.confirm({\n message:\n \"Enable dedicated IP? (Requires 100k+ emails/day, adds ~$50-100/mo)\",\n initialValue: false,\n });\n\n if (clack.isCancel(confirmed)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n if (!confirmed) {\n clack.log.info(\"Dedicated IP not enabled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n dedicatedIp: true,\n };\n newPreset = undefined; // Custom config\n break;\n }\n\n case \"custom\": {\n // Full custom configuration\n const { promptCustomConfig } = await import(\n \"../../utils/shared/prompts.js\"\n );\n\n // Pass existing config to preserve values\n const customConfig = await promptCustomConfig(config);\n\n // Apply custom config updates to existing config (preserves user-customized fields)\n updatedConfig = applyConfigUpdates(config, customConfig);\n newPreset = undefined;\n break;\n }\n }\n\n // 8. Show cost comparison\n const newCostData = calculateCosts(updatedConfig, 50_000);\n const costDiff = newCostData.total.monthly - currentCostData.total.monthly;\n\n console.log(`\\n${pc.bold(\"Cost Impact:\")}`);\n console.log(\n ` Current: ${pc.cyan(`${formatCost(currentCostData.total.monthly)}/mo`)}`\n );\n console.log(\n ` New: ${pc.cyan(`${formatCost(newCostData.total.monthly)}/mo`)}`\n );\n if (costDiff > 0) {\n console.log(` Change: ${pc.yellow(`+${formatCost(costDiff)}/mo`)}`);\n } else if (costDiff < 0) {\n console.log(\n ` Change: ${pc.green(`${formatCost(Math.abs(costDiff))}/mo`)}`\n );\n }\n console.log(\"\");\n\n // 9. Confirm upgrade (skip if --yes or --preview)\n if (!(options.yes || options.preview)) {\n const confirmed = await clack.confirm({\n message: \"Proceed with upgrade?\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n }\n\n // 10. Get Vercel config if needed and not already stored\n let vercelConfig;\n if (metadata.provider === \"vercel\" && !metadata.vercel) {\n vercelConfig = await promptVercelConfig();\n } else if (metadata.provider === \"vercel\") {\n vercelConfig = metadata.vercel;\n }\n\n // 11. Build stack configuration\n const stackConfig: EmailStackConfig = {\n provider: metadata.provider,\n region,\n vercel: vercelConfig,\n emailConfig: updatedConfig,\n };\n\n // 12. Preview or Update Pulumi stack\n if (options.preview) {\n // PREVIEW MODE - show what would be changed without deploying\n try {\n const previewResult = await progress.execute(\n \"Generating upgrade preview\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName:\n metadata.services.email?.pulumiStackName ||\n `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n httpsTrackingEnabled: result.httpsTrackingEnabled,\n cloudFrontDomain: result.cloudFrontDomain,\n acmCertificateValidationRecords:\n result.acmCertificateValidationRecords,\n archiveArn: result.archiveArn,\n archivingEnabled: result.archivingEnabled,\n archiveRetention: result.archiveRetention,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Refresh state to sync with AWS before previewing\n await stack.refresh({ onOutput: () => {} });\n\n // Run preview instead of deployment\n const result = await stack.preview({ diff: true });\n return result;\n }\n );\n\n // Build cost comparison string\n const costComparison = [\n `Current: ${formatCost(currentCostData.total.monthly)}/mo`,\n `After upgrade: ${formatCost(newCostData.total.monthly)}/mo`,\n costDiff > 0\n ? `Change: +${formatCost(costDiff)}/mo`\n : costDiff < 0\n ? `Change: -${formatCost(Math.abs(costDiff))}/mo`\n : \"Change: No cost difference\",\n ].join(\"\\n\");\n\n // Display preview results\n displayPreview({\n changeSummary: previewResult.changeSummary,\n costEstimate: costComparison,\n commandName: \"wraps email upgrade\",\n });\n\n clack.outro(\n pc.green(\"Preview complete. Run without --preview to upgrade.\")\n );\n\n // Track preview completion\n trackServiceUpgrade(\"email\", {\n from_preset: metadata.services.email?.preset,\n to_preset: newPreset,\n preview: true,\n action: typeof upgradeAction === \"string\" ? upgradeAction : undefined,\n duration_ms: Date.now() - startTime,\n });\n return;\n } catch (error: any) {\n trackError(\"PREVIEW_FAILED\", \"email:upgrade\", { step: \"preview\" });\n if (error.message?.includes(\"stack is currently locked\")) {\n throw errors.stackLocked();\n }\n throw new Error(`Preview failed: ${error.message}`);\n }\n }\n\n // DEPLOY MODE - actually update infrastructure\n let outputs;\n try {\n outputs = await progress.execute(\n \"Updating Wraps infrastructure (this may take 2-3 minutes)\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName:\n metadata.services.email?.pulumiStackName ||\n `wraps-${identity.accountId}-${region}`,\n projectName: \"wraps-email\",\n program: async () => {\n const result = await deployEmailStack(stackConfig);\n\n return {\n roleArn: result.roleArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n domain: result.domain,\n dkimTokens: result.dkimTokens,\n customTrackingDomain: result.customTrackingDomain,\n httpsTrackingEnabled: result.httpsTrackingEnabled,\n cloudFrontDomain: result.cloudFrontDomain,\n acmCertificateValidationRecords:\n result.acmCertificateValidationRecords,\n archiveArn: result.archiveArn,\n archivingEnabled: result.archivingEnabled,\n archiveRetention: result.archiveRetention,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.workspace.selectStack(\n metadata.services.email?.pulumiStackName ||\n `wraps-${identity.accountId}-${region}`\n );\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Refresh state to sync with AWS before upgrading\n // This ensures Pulumi knows about resources that already exist\n await stack.refresh({ onOutput: () => {} });\n\n // Pulumi will automatically detect changes and only update what's needed\n const upResult = await stack.up({ onOutput: () => {} });\n const pulumiOutputs = upResult.outputs;\n\n return {\n roleArn: pulumiOutputs.roleArn?.value as string,\n configSetName: pulumiOutputs.configSetName?.value as\n | string\n | undefined,\n tableName: pulumiOutputs.tableName?.value as string | undefined,\n region: pulumiOutputs.region?.value as string,\n lambdaFunctions: pulumiOutputs.lambdaFunctions?.value as\n | string[]\n | undefined,\n domain: pulumiOutputs.domain?.value as string | undefined,\n dkimTokens: pulumiOutputs.dkimTokens?.value as string[] | undefined,\n customTrackingDomain: pulumiOutputs.customTrackingDomain?.value as\n | string\n | undefined,\n httpsTrackingEnabled: pulumiOutputs.httpsTrackingEnabled?.value as\n | boolean\n | undefined,\n cloudFrontDomain: pulumiOutputs.cloudFrontDomain?.value as\n | string\n | undefined,\n acmCertificateValidationRecords: pulumiOutputs\n .acmCertificateValidationRecords?.value as\n | Array<{ name: string; type: string; value: string }>\n | undefined,\n archiveArn: pulumiOutputs.archiveArn?.value as string | undefined,\n archivingEnabled: pulumiOutputs.archivingEnabled?.value as\n | boolean\n | undefined,\n archiveRetention: pulumiOutputs.archiveRetention?.value as\n | string\n | undefined,\n };\n }\n );\n } catch (error: any) {\n // Track upgrade failure\n trackServiceUpgrade(\"email\", {\n from_preset: metadata.services.email?.preset,\n to_preset: newPreset,\n action: typeof upgradeAction === \"string\" ? upgradeAction : undefined,\n duration_ms: Date.now() - startTime,\n });\n\n // Check if it's a lock file error\n if (error.message?.includes(\"stack is currently locked\")) {\n trackError(\"STACK_LOCKED\", \"email:upgrade\", { step: \"deploy\" });\n throw errors.stackLocked();\n }\n\n trackError(\"UPGRADE_FAILED\", \"email:upgrade\", { step: \"deploy\" });\n throw new Error(`Pulumi upgrade failed: ${error.message}`);\n }\n\n // 13. Create DNS records in Route53 (if hosted zone exists)\n if (outputs.domain && outputs.dkimTokens && outputs.dkimTokens.length > 0) {\n const { findHostedZone, createDNSRecords } = await import(\n \"../../utils/route53.js\"\n );\n const hostedZone = await findHostedZone(outputs.domain, region);\n\n if (hostedZone) {\n try {\n progress.start(\"Creating DNS records in Route53\");\n\n // Determine mailFromDomain - use updatedConfig if available, otherwise construct default\n const mailFromDomain =\n updatedConfig.mailFromDomain || `mail.${outputs.domain}`;\n\n await createDNSRecords(\n hostedZone.id,\n outputs.domain,\n outputs.dkimTokens,\n region,\n outputs.customTrackingDomain,\n mailFromDomain,\n outputs.cloudFrontDomain\n );\n progress.succeed(\"DNS records created in Route53\");\n } catch (error: any) {\n progress.fail(\n `Failed to create DNS records automatically: ${error.message}`\n );\n progress.info(\n \"You can manually add the required DNS records shown below\"\n );\n }\n }\n }\n\n // 14. Update metadata\n updateEmailConfig(metadata, updatedConfig);\n if (metadata.services.email) {\n metadata.services.email.preset = newPreset as any;\n }\n await saveConnectionMetadata(metadata);\n\n progress.info(\"Connection metadata updated\");\n\n // 15. Format tracking domain DNS records if custom tracking domain was added\n const trackingDomainDnsRecords = [];\n const acmValidationRecords = [];\n\n if (outputs.customTrackingDomain) {\n // For HTTPS tracking, only show CNAME if CloudFront exists\n // For HTTP tracking, point to SES tracking endpoint\n if (outputs.httpsTrackingEnabled) {\n // Only add tracking domain CNAME if CloudFront is created\n if (outputs.cloudFrontDomain) {\n trackingDomainDnsRecords.push({\n name: outputs.customTrackingDomain,\n type: \"CNAME\",\n value: outputs.cloudFrontDomain,\n });\n }\n } else {\n // HTTP tracking - use SES tracking endpoint\n trackingDomainDnsRecords.push({\n name: outputs.customTrackingDomain,\n type: \"CNAME\",\n value: `r.${outputs.region}.awstrack.me`,\n });\n }\n }\n\n // Add ACM certificate validation records if HTTPS tracking is enabled\n if (outputs.httpsTrackingEnabled && outputs.acmCertificateValidationRecords) {\n acmValidationRecords.push(...outputs.acmCertificateValidationRecords);\n }\n\n // Check if HTTPS tracking was enabled but CloudFront wasn't created (manual DNS validation needed)\n const needsCertificateValidation =\n outputs.httpsTrackingEnabled &&\n acmValidationRecords.length > 0 &&\n !outputs.cloudFrontDomain;\n\n // 15. Display success message\n displaySuccess({\n roleArn: outputs.roleArn,\n configSetName: outputs.configSetName,\n region: outputs.region!,\n tableName: outputs.tableName,\n trackingDomainDnsRecords:\n trackingDomainDnsRecords.length > 0\n ? trackingDomainDnsRecords\n : undefined,\n acmValidationRecords:\n acmValidationRecords.length > 0 ? acmValidationRecords : undefined,\n customTrackingDomain: outputs.customTrackingDomain,\n httpsTrackingEnabled: outputs.httpsTrackingEnabled,\n });\n\n // Show what was upgraded\n console.log(`\\n${pc.green(\"✓\")} ${pc.bold(\"Upgrade complete!\")}\\n`);\n\n if (upgradeAction === \"preset\" && newPreset) {\n console.log(\n `Upgraded to ${pc.cyan(newPreset)} preset (${pc.green(`${formatCost(newCostData.total.monthly)}/mo`)})\\n`\n );\n } else {\n console.log(\n `Updated configuration (${pc.green(`${formatCost(newCostData.total.monthly)}/mo`)})\\n`\n );\n }\n\n // Show next steps for HTTPS tracking if certificate validation is pending\n if (needsCertificateValidation) {\n console.log(pc.bold(\"⚠️ HTTPS Tracking - Next Steps:\\n\"));\n console.log(\n \" 1. Add the SSL certificate validation DNS record shown above to your DNS provider\"\n );\n console.log(\n \" 2. Wait for DNS propagation and certificate validation (5-30 minutes)\"\n );\n console.log(\n ` 3. Run ${pc.cyan(\"wraps email upgrade\")} again to complete CloudFront setup\\n`\n );\n console.log(\n pc.dim(\n \" Note: CloudFront distribution will be created once the certificate is validated.\\n\"\n )\n );\n } else if (outputs.httpsTrackingEnabled && outputs.cloudFrontDomain) {\n console.log(\n pc.green(\"✓\") +\n \" \" +\n pc.bold(\"HTTPS tracking is fully configured and ready to use!\\n\")\n );\n }\n\n // 16. Track successful upgrade\n const enabledFeatures: string[] = [];\n if (updatedConfig.tracking?.enabled) enabledFeatures.push(\"tracking\");\n if (updatedConfig.suppressionList?.enabled)\n enabledFeatures.push(\"suppression_list\");\n if (updatedConfig.eventTracking?.enabled)\n enabledFeatures.push(\"event_tracking\");\n if (updatedConfig.eventTracking?.dynamoDBHistory)\n enabledFeatures.push(\"dynamodb_history\");\n if (updatedConfig.dedicatedIp) enabledFeatures.push(\"dedicated_ip\");\n if (updatedConfig.emailArchiving?.enabled)\n enabledFeatures.push(\"email_archiving\");\n\n trackServiceUpgrade(\"email\", {\n from_preset: metadata.services.email?.preset,\n to_preset: newPreset,\n added_features: enabledFeatures,\n action: typeof upgradeAction === \"string\" ? upgradeAction : undefined,\n duration_ms: Date.now() - startTime,\n });\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport getPort from \"get-port\";\nimport open from \"open\";\nimport pc from \"picocolors\";\nimport { startConsoleServer } from \"../../console/server.js\";\nimport { trackCommand } from \"../../telemetry/events.js\";\nimport type { DashboardOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport { loadConnectionMetadata } from \"../../utils/shared/metadata.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\n\n/**\n * Dashboard command - Start local web dashboard\n */\nexport async function dashboard(options: DashboardOptions): Promise<void> {\n clack.intro(pc.bold(\"Wraps Dashboard\"));\n\n const progress = new DeploymentProgress();\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region\n const region = await getAWSRegion();\n\n // 3. Load stack outputs to get configuration\n let emailStackOutputs: any = {};\n let smsStackOutputs: any = {};\n\n try {\n // Ensure Pulumi workspace is configured (sets backend URL)\n await ensurePulumiWorkDir();\n\n // Try to load email stack\n try {\n const emailStack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName: `wraps-${identity.accountId}-${region}`,\n workDir: getPulumiWorkDir(),\n });\n emailStackOutputs = await emailStack.outputs();\n } catch (_emailError: unknown) {\n // Email stack not found, continue\n }\n\n // Try to load SMS stack\n try {\n const smsStack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName: `wraps-sms-${identity.accountId}-${region}`,\n workDir: getPulumiWorkDir(),\n });\n smsStackOutputs = await smsStack.outputs();\n } catch (_smsError: unknown) {\n // SMS stack not found, continue\n }\n\n // If neither stack found, show error\n if (\n Object.keys(emailStackOutputs).length === 0 &&\n Object.keys(smsStackOutputs).length === 0\n ) {\n throw new Error(\"No infrastructure found\");\n }\n } catch (_error: unknown) {\n progress.stop();\n clack.log.error(\"No Wraps infrastructure found\");\n console.log(\n `\\\\nRun ${pc.cyan(\"wraps email init\")} or ${pc.cyan(\"wraps sms init\")} to deploy infrastructure first.\\\\n`\n );\n process.exit(1);\n }\n\n // Extract email outputs\n const tableName = emailStackOutputs.tableName?.value;\n const archiveArn = emailStackOutputs.archiveArn?.value;\n const archivingEnabled = emailStackOutputs.archivingEnabled?.value ?? false;\n\n // Extract SMS outputs\n const smsTableName = smsStackOutputs.tableName?.value;\n const smsPhoneNumber = smsStackOutputs.phoneNumber?.value;\n const smsPhoneNumberArn = smsStackOutputs.phoneNumberArn?.value;\n const smsPhoneNumberType = smsStackOutputs.phoneNumberType?.value;\n const smsConfigSetName = smsStackOutputs.configSetName?.value;\n\n // Load SMS config from metadata for protect configuration and event tracking\n let smsProtectEnabled = false;\n let smsAllowedCountries: string[] | undefined;\n let smsAitFiltering: boolean | undefined;\n let smsArchiveRetention: string | undefined;\n\n try {\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n if (metadata?.services?.sms?.config) {\n const smsConfig = metadata.services.sms.config;\n if (smsConfig.protectConfiguration) {\n smsProtectEnabled = smsConfig.protectConfiguration.enabled ?? false;\n smsAllowedCountries = smsConfig.protectConfiguration.allowedCountries;\n smsAitFiltering = smsConfig.protectConfiguration.aitFiltering;\n }\n if (smsConfig.eventTracking?.archiveRetention) {\n smsArchiveRetention = smsConfig.eventTracking.archiveRetention;\n }\n }\n } catch {\n // Metadata load failed, continue with defaults\n }\n\n // 4. Find available port\n const port =\n options.port || (await getPort({ port: [5555, 5556, 5557, 5558, 5559] }));\n\n // 5. Start server\n progress.stop();\n clack.log.success(\"Starting dashboard server...\");\n console.log(\n `${pc.dim(\"Using current AWS credentials (no role assumption)\")}\\\\n`\n );\n\n const { url } = await startConsoleServer({\n port,\n roleArn: undefined, // Use current credentials instead of assuming role\n region,\n tableName,\n accountId: identity.accountId,\n noOpen: options.noOpen ?? false,\n archiveArn,\n archivingEnabled,\n // SMS config\n smsTableName,\n smsPhoneNumber,\n smsPhoneNumberArn,\n smsPhoneNumberType,\n smsConfigSetName,\n smsProtectEnabled,\n smsAllowedCountries,\n smsAitFiltering,\n smsArchiveRetention,\n });\n\n console.log(`\\\\n${pc.bold(\"Dashboard:\")} ${pc.cyan(url)}`);\n console.log(`${pc.dim(\"Press Ctrl+C to stop\")}\\\\n`);\n\n // 6. Open browser (unless --no-open)\n if (!options.noOpen) {\n await open(url);\n }\n\n // 7. Track console launch\n trackCommand(\"console\", {\n success: true,\n port,\n no_open: options.noOpen ?? false,\n });\n\n // Keep process alive\n await new Promise(() => {});\n}\n","import crypto from \"node:crypto\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport express from \"express\";\nimport { createHttpTerminator } from \"http-terminator\";\nimport { authenticateToken } from \"./middleware/auth.js\";\nimport { errorHandler } from \"./middleware/error.js\";\nimport { createDomainsRouter } from \"./routes/domains.js\";\nimport { createEmailsRouter } from \"./routes/emails.js\";\nimport { createMetricsRouter } from \"./routes/metrics.js\";\nimport { createSettingsRouter } from \"./routes/settings.js\";\nimport { createSMSRouter } from \"./routes/sms.js\";\nimport { createUserRouter } from \"./routes/user.js\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport type ServerConfig = {\n port: number;\n roleArn: string | undefined;\n region: string;\n tableName?: string;\n accountId?: string;\n noOpen: boolean;\n archiveArn?: string;\n archivingEnabled?: boolean;\n // SMS config\n smsTableName?: string;\n smsPhoneNumber?: string;\n smsPhoneNumberArn?: string;\n smsPhoneNumberType?: string;\n smsConfigSetName?: string;\n smsProtectEnabled?: boolean;\n smsAllowedCountries?: string[];\n smsAitFiltering?: boolean;\n smsArchiveRetention?: string;\n};\n\nexport type ServerInfo = {\n url: string;\n token: string;\n};\n\n/**\n * Start console server\n */\nexport async function startConsoleServer(\n config: ServerConfig\n): Promise<ServerInfo> {\n const app = express();\n\n // Generate auth token\n const authToken = crypto.randomBytes(32).toString(\"hex\");\n\n // Middleware\n app.use(express.json());\n\n // Simple rate limiting for static file requests (defense-in-depth)\n // Note: This is a localhost-only dev server with token auth, so this is just\n // a safeguard against accidental abuse or runaway scripts\n const requestCounts = new Map<string, { count: number; resetTime: number }>();\n const RATE_LIMIT_WINDOW = 60 * 1000; // 1 minute\n const RATE_LIMIT_MAX_REQUESTS = 1000; // 1000 requests per minute per IP\n\n app.use((req, res, next) => {\n const ip = req.ip || req.socket.remoteAddress || \"unknown\";\n const now = Date.now();\n const record = requestCounts.get(ip);\n\n if (!record || now > record.resetTime) {\n // New window\n requestCounts.set(ip, { count: 1, resetTime: now + RATE_LIMIT_WINDOW });\n next();\n } else if (record.count < RATE_LIMIT_MAX_REQUESTS) {\n // Within limit\n record.count++;\n next();\n } else {\n // Rate limit exceeded\n res.status(429).json({\n error: \"Too many requests, please slow down\",\n retryAfter: Math.ceil((record.resetTime - now) / 1000),\n });\n }\n });\n\n // Security headers\n app.use((_req, res, next) => {\n res.setHeader(\"X-Frame-Options\", \"DENY\");\n res.setHeader(\"X-Content-Type-Options\", \"nosniff\");\n res.setHeader(\n \"Content-Security-Policy\",\n \"default-src 'self' 'unsafe-inline' 'unsafe-eval'; \" +\n \"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; \" +\n \"font-src 'self' https://fonts.gstatic.com; \" +\n \"connect-src 'self'\"\n );\n next();\n });\n\n // Request logging middleware\n app.use((req, _res, next) => {\n console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);\n next();\n });\n\n // API routes (with authentication)\n app.use(\n \"/api/metrics\",\n authenticateToken(authToken),\n createMetricsRouter(config)\n );\n app.use(\n \"/api/domains\",\n authenticateToken(authToken),\n createDomainsRouter(config)\n );\n app.use(\n \"/api/emails\",\n authenticateToken(authToken),\n createEmailsRouter(config)\n );\n app.use(\n \"/api/settings\",\n authenticateToken(authToken),\n createSettingsRouter(config)\n );\n app.use(\"/api/user\", authenticateToken(authToken), createUserRouter(config));\n app.use(\"/api/sms\", authenticateToken(authToken), createSMSRouter(config));\n\n // Serve static files from console-ui build\n // __dirname will be dist/ after compilation, console UI is in dist/console/\n const staticDir = path.join(__dirname, \"console\");\n app.use(express.static(staticDir));\n\n // SPA fallback\n app.get(\"*\", (_req, res) => {\n res.sendFile(path.join(staticDir, \"index.html\"));\n });\n\n // Error handler\n app.use(errorHandler);\n\n // Start server\n const server = app.listen(config.port, \"127.0.0.1\");\n\n // Setup graceful shutdown\n const httpTerminator = createHttpTerminator({ server });\n\n process.on(\"SIGTERM\", async () => {\n console.log(\"\\\\nShutting down gracefully...\");\n await httpTerminator.terminate();\n process.exit(0);\n });\n\n process.on(\"SIGINT\", async () => {\n console.log(\"\\\\nShutting down gracefully...\");\n await httpTerminator.terminate();\n process.exit(0);\n });\n\n const url = `http://localhost:${config.port}?token=${authToken}`;\n\n return { url, token: authToken };\n}\n","import type { NextFunction, Request, Response } from \"express\";\n\n/**\n * Token-based authentication middleware\n */\nexport function authenticateToken(expectedToken: string) {\n return (req: Request, res: Response, next: NextFunction) => {\n // Get token from query param or header\n const token = req.query.token || req.headers[\"x-auth-token\"];\n\n if (!token || token !== expectedToken) {\n return res.status(401).json({ error: \"Unauthorized\" });\n }\n\n next();\n };\n}\n","import type { NextFunction, Request, Response } from \"express\";\n\n/**\n * Error handling middleware\n */\nexport function errorHandler(\n err: Error,\n _req: Request,\n res: Response,\n _next: NextFunction\n) {\n console.error(\"Server error:\", err);\n\n res.status(500).json({\n error: \"Internal server error\",\n message: err.message,\n });\n}\n","import type { Request, Response, Router } from \"express\";\nimport { Router as createRouter } from \"express\";\nimport type { ServerConfig } from \"../server.js\";\nimport { fetchDomainInfo } from \"../services/ses-service.js\";\n\nexport function createDomainsRouter(config: ServerConfig): Router {\n const router = createRouter();\n\n /**\n * Get domain verification status\n */\n router.get(\"/:domain\", async (req: Request, res: Response) => {\n try {\n const { domain } = req.params;\n\n if (!domain) {\n return res.status(400).json({ error: \"Domain parameter required\" });\n }\n\n const domainInfo = await fetchDomainInfo(\n config.roleArn,\n config.region,\n domain\n );\n\n res.json(domainInfo);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n res.status(500).json({ error: errorMessage });\n }\n });\n\n return router;\n}\n","import { GetSendQuotaCommand, SESClient } from \"@aws-sdk/client-ses\";\nimport { GetEmailIdentityCommand, SESv2Client } from \"@aws-sdk/client-sesv2\";\nimport { assumeRole } from \"../../utils/shared/assume-role.js\";\n\nexport type SendQuota = {\n max24HourSend: number;\n maxSendRate: number;\n sentLast24Hours: number;\n};\n\nexport type DomainInfo = {\n domain: string;\n verified: boolean;\n dkimStatus: string;\n dkimTokens: string[];\n};\n\n/**\n * Fetch SES send quota\n */\nexport async function fetchSendQuota(\n roleArn: string | undefined,\n region: string\n): Promise<SendQuota> {\n // For console usage, use current credentials instead of assuming role\n const credentials = roleArn ? await assumeRole(roleArn, region) : undefined;\n const ses = new SESClient({ region, credentials });\n\n const response = await ses.send(new GetSendQuotaCommand({}));\n\n return {\n max24HourSend: response.Max24HourSend || 0,\n maxSendRate: response.MaxSendRate || 0,\n sentLast24Hours: response.SentLast24Hours || 0,\n };\n}\n\n/**\n * Fetch domain verification status\n */\nexport async function fetchDomainInfo(\n roleArn: string | undefined,\n region: string,\n domain: string\n): Promise<DomainInfo> {\n // For console usage, use current credentials instead of assuming role\n const credentials = roleArn ? await assumeRole(roleArn, region) : undefined;\n const sesv2 = new SESv2Client({ region, credentials });\n\n const response = await sesv2.send(\n new GetEmailIdentityCommand({\n EmailIdentity: domain,\n })\n );\n\n return {\n domain,\n verified: response.VerifiedForSendingStatus ?? false,\n dkimStatus: response.DkimAttributes?.Status || \"PENDING\",\n dkimTokens: response.DkimAttributes?.Tokens || [],\n };\n}\n","import type { Request, Response, Router } from \"express\";\nimport { Router as createRouter } from \"express\";\nimport type { ServerConfig } from \"../server.js\";\nimport { fetchEmailById, fetchEmailLogs } from \"../services/email-logs.js\";\n\nexport function createEmailsRouter(config: ServerConfig): Router {\n const router = createRouter();\n\n /**\n * Get email logs\n */\n router.get(\"/\", async (req: Request, res: Response) => {\n try {\n console.log(\"Email logs request received\");\n console.log(\"Query params:\", req.query);\n console.log(\"Config:\", {\n tableName: config.tableName,\n region: config.region,\n accountId: config.accountId,\n });\n\n // Parse query parameters\n const limit = req.query.limit\n ? Number.parseInt(req.query.limit as string, 10)\n : 100;\n const startTime = req.query.startTime\n ? Number.parseInt(req.query.startTime as string, 10)\n : undefined;\n const endTime = req.query.endTime\n ? Number.parseInt(req.query.endTime as string, 10)\n : undefined;\n\n if (!config.tableName) {\n console.log(\"No table name configured\");\n return res.status(400).json({\n error:\n \"Email tracking not enabled. Deploy with enhanced integration to enable email logs.\",\n });\n }\n\n console.log(\"Fetching email logs from DynamoDB...\");\n const logs = await fetchEmailLogs({\n region: config.region,\n tableName: config.tableName,\n accountId: config.accountId,\n limit,\n startTime,\n endTime,\n });\n\n console.log(`Found ${logs.length} email logs`);\n res.json({ logs });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching email logs:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Get email details by ID\n */\n router.get(\"/:id\", async (req: Request, res: Response) => {\n try {\n const { id } = req.params;\n console.log(\"Email detail request received for ID:\", id);\n console.log(\"Request headers:\", req.headers);\n console.log(\"Request query:\", req.query);\n\n if (!config.tableName) {\n console.log(\"No table name configured\");\n return res.status(400).json({\n error:\n \"Email tracking not enabled. Deploy with enhanced integration to enable email logs.\",\n });\n }\n\n console.log(\"Fetching email details from DynamoDB...\");\n const email = await fetchEmailById(id, {\n region: config.region,\n tableName: config.tableName,\n });\n\n if (!email) {\n console.log(\"Email not found for ID:\", id);\n return res.status(404).json({ error: \"Email not found\" });\n }\n\n console.log(\"Email details found:\", email.messageId);\n console.log(\"Sending response with\", email.events.length, \"events\");\n res.json(email);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching email details:\", error);\n console.error(\n \"Stack trace:\",\n error instanceof Error ? error.stack : \"N/A\"\n );\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Get archived email content by message ID\n */\n router.get(\"/:id/archive\", async (req: Request, res: Response) => {\n try {\n const { id } = req.params;\n console.log(\"Archived email request received for message ID:\", id);\n\n if (!config.archivingEnabled) {\n console.log(\"Email archiving not enabled\");\n return res.status(400).json({\n error: \"Email archiving not enabled for this deployment.\",\n });\n }\n\n if (!config.archiveArn) {\n console.log(\"No archive ARN configured\");\n return res.status(400).json({\n error: \"Archive ARN not configured.\",\n });\n }\n\n if (!config.tableName) {\n console.log(\"No table name configured\");\n return res.status(400).json({\n error:\n \"Email tracking not enabled. Need email metadata to search archive.\",\n });\n }\n\n // First, fetch email details from DynamoDB to get search metadata\n console.log(\"Fetching email metadata from DynamoDB...\");\n const emailDetails = await fetchEmailById(id, {\n region: config.region,\n tableName: config.tableName,\n });\n\n if (!emailDetails) {\n console.log(\"Email metadata not found in DynamoDB for ID:\", id);\n return res.status(404).json({\n error: \"Email metadata not found. Cannot search archive.\",\n });\n }\n\n console.log(\"Fetching archived email from Mail Manager...\");\n const { fetchArchivedEmail } = await import(\n \"../services/email-archive.js\"\n );\n const archivedEmail = await fetchArchivedEmail(id, {\n region: config.region,\n archiveArn: config.archiveArn,\n from: emailDetails.from,\n to: emailDetails.to[0], // Use first recipient for search\n subject: emailDetails.subject,\n timestamp: new Date(emailDetails.sentAt),\n });\n\n if (!archivedEmail) {\n console.log(\"Archived email not found for message ID:\", id);\n return res.status(404).json({\n error:\n \"Archived email not found. It may have been sent before archiving was enabled.\",\n });\n }\n\n console.log(\"Archived email found:\", archivedEmail.messageId);\n res.json(archivedEmail);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching archived email:\", error);\n console.error(\n \"Stack trace:\",\n error instanceof Error ? error.stack : \"N/A\"\n );\n res.status(500).json({ error: errorMessage });\n }\n });\n\n return router;\n}\n","import {\n DynamoDBClient,\n QueryCommand,\n ScanCommand,\n} from \"@aws-sdk/client-dynamodb\";\nimport { unmarshall } from \"@aws-sdk/util-dynamodb\";\n\nexport type EmailLog = {\n messageId: string;\n to: string[]; // Array of recipients\n from: string;\n subject: string;\n status:\n | \"delivered\"\n | \"bounced\"\n | \"complained\"\n | \"sent\"\n | \"failed\"\n | \"opened\"\n | \"clicked\";\n sentAt: number;\n accountId?: string;\n errorMessage?: string;\n};\n\nexport type EmailEvent = {\n type:\n | \"sent\"\n | \"delivered\"\n | \"bounced\"\n | \"complained\"\n | \"opened\"\n | \"clicked\"\n | \"failed\";\n timestamp: number;\n metadata?: Record<string, any>;\n};\n\nexport type EmailDetails = {\n id: string;\n messageId: string;\n from: string;\n to: string[];\n replyTo?: string;\n subject: string;\n htmlBody?: string;\n textBody?: string;\n status:\n | \"delivered\"\n | \"bounced\"\n | \"complained\"\n | \"sent\"\n | \"failed\"\n | \"opened\"\n | \"clicked\";\n sentAt: number;\n events: EmailEvent[];\n};\n\ntype FetchEmailLogsOptions = {\n region: string;\n tableName: string;\n accountId?: string;\n limit?: number;\n startTime?: number;\n endTime?: number;\n};\n\n/**\n * Fetch email logs from DynamoDB\n */\nexport async function fetchEmailLogs(\n options: FetchEmailLogsOptions\n): Promise<EmailLog[]> {\n const {\n region,\n tableName,\n accountId,\n limit = 100,\n startTime,\n endTime,\n } = options;\n\n const dynamodb = new DynamoDBClient({ region });\n\n try {\n // If we have accountId, use GSI for better performance\n let items: any[] = [];\n if (accountId) {\n let keyConditionExpression = \"accountId = :accountId\";\n const expressionAttributeValues: Record<string, any> = {\n \":accountId\": { S: accountId },\n };\n\n // Add time range if provided\n if (startTime && endTime) {\n keyConditionExpression += \" AND sentAt BETWEEN :startTime AND :endTime\";\n expressionAttributeValues[\":startTime\"] = { N: startTime.toString() };\n expressionAttributeValues[\":endTime\"] = { N: endTime.toString() };\n } else if (startTime) {\n keyConditionExpression += \" AND sentAt >= :startTime\";\n expressionAttributeValues[\":startTime\"] = { N: startTime.toString() };\n }\n\n const response = await dynamodb.send(\n new QueryCommand({\n TableName: tableName,\n IndexName: \"accountId-sentAt-index\",\n KeyConditionExpression: keyConditionExpression,\n ExpressionAttributeValues: expressionAttributeValues,\n ScanIndexForward: false, // Sort by sentAt descending (newest first)\n })\n );\n\n items = response.Items || [];\n } else {\n // Otherwise, scan the table (less efficient but works without accountId)\n const response = await dynamodb.send(\n new ScanCommand({\n TableName: tableName,\n })\n );\n\n items = response.Items || [];\n }\n\n // Unmarshall all items\n const unmarshalled = items.map((item) => unmarshall(item));\n\n // Group events by messageId to get the latest status for each email\n const emailMap = new Map<string, any>();\n\n for (const item of unmarshalled) {\n const messageId = item.messageId;\n const existing = emailMap.get(messageId);\n\n if (existing) {\n // Keep the event with the most important status\n // Priority: Complaint > Permanent Bounce > Delivery > Transient Bounce > Send\n const currentPriority = getEventPriority(item);\n const existingPriority = getEventPriority(existing);\n\n if (currentPriority > existingPriority) {\n emailMap.set(messageId, item);\n }\n } else {\n emailMap.set(messageId, item);\n }\n }\n\n // Convert map to array and normalize\n const logs = Array.from(emailMap.values())\n .map(normalizeEmailLog)\n .sort((a, b) => b.sentAt - a.sentAt);\n\n // Apply limit\n return logs.slice(0, limit);\n } catch (error) {\n console.error(\"Error fetching email logs:\", error);\n throw error;\n }\n}\n\n/**\n * Get priority for event type (higher = more important to display)\n * Priority: Complaint > Permanent Bounce > Click > Open > Delivery > Transient Bounce > Send\n */\nfunction getEventPriority(item: any): number {\n const type = item.eventType?.toLowerCase();\n\n switch (type) {\n case \"complaint\":\n return 7;\n case \"bounce\": {\n // Permanent bounces (hard bounces) are more important than delivery\n // Transient bounces (OOTO, mailbox full) are less important than delivery\n const bounceType = item.bounceType?.toLowerCase();\n return bounceType === \"permanent\" ? 6 : 2;\n }\n case \"click\":\n return 5;\n case \"open\":\n return 4;\n case \"delivery\":\n return 3;\n case \"send\":\n return 1;\n default:\n return 0;\n }\n}\n\n/**\n * Normalize email log data from DynamoDB\n */\nfunction normalizeEmailLog(data: any): EmailLog {\n // Determine status based on eventType\n let status: EmailLog[\"status\"] = \"sent\";\n const eventType = data.eventType?.toLowerCase();\n\n if (eventType === \"complaint\") {\n status = \"complained\";\n } else if (eventType === \"bounce\") {\n status = \"bounced\";\n } else if (eventType === \"click\") {\n status = \"clicked\";\n } else if (eventType === \"open\") {\n status = \"opened\";\n } else if (eventType === \"delivery\") {\n status = \"delivered\";\n } else if (eventType === \"send\") {\n status = \"sent\";\n } else if (data.errorMessage) {\n status = \"failed\";\n }\n\n // Handle 'to' field - it's stored as a String Set in DynamoDB\n // DynamoDB String Sets get unmarshalled as JavaScript Set objects\n let toAddresses: string[] = [];\n const toField = data.to || data.destination; // CSV export might show as 'destination'\n\n if (toField) {\n console.log(\n \"Raw 'to' field:\",\n toField,\n \"Type:\",\n typeof toField,\n \"Constructor:\",\n toField.constructor?.name\n );\n\n if (toField instanceof Set) {\n // DynamoDB String Set -> JavaScript Set\n toAddresses = Array.from(toField);\n } else if (Array.isArray(toField)) {\n toAddresses = toField;\n } else if (typeof toField === \"string\") {\n toAddresses = [toField];\n }\n }\n\n console.log(\"Normalized toAddresses:\", toAddresses);\n\n return {\n messageId: data.messageId,\n to: toAddresses,\n from: data.from || \"unknown\",\n subject: data.subject || \"(no subject)\",\n status,\n sentAt: Number(data.sentAt),\n accountId: data.accountId,\n errorMessage: data.errorMessage,\n };\n}\n\n/**\n * Fetch email details by message ID (with all events)\n */\nexport async function fetchEmailById(\n messageId: string,\n options: { region: string; tableName: string }\n): Promise<EmailDetails | null> {\n const { region, tableName } = options;\n const dynamodb = new DynamoDBClient({ region });\n\n try {\n // Query all events for this messageId\n const response = await dynamodb.send(\n new QueryCommand({\n TableName: tableName,\n KeyConditionExpression: \"messageId = :messageId\",\n ExpressionAttributeValues: {\n \":messageId\": { S: messageId },\n },\n })\n );\n\n const items = response.Items || [];\n\n if (items.length === 0) {\n return null;\n }\n\n // Unmarshall all events\n const events = items.map((item) => unmarshall(item));\n\n // Get the send event (has the email content)\n const sendEvent = events.find((e) => e.eventType?.toLowerCase() === \"send\");\n\n if (!sendEvent) {\n return null;\n }\n\n console.log(\"Send event fields:\", {\n from: sendEvent.from,\n source: sendEvent.source,\n subject: sendEvent.subject,\n to: sendEvent.to,\n destination: sendEvent.destination,\n availableKeys: Object.keys(sendEvent),\n });\n\n // Try to extract email content from eventData\n let htmlBody: string | undefined;\n let textBody: string | undefined;\n\n if (sendEvent.eventData) {\n try {\n const eventData = JSON.parse(sendEvent.eventData);\n console.log(\"Send event data keys:\", Object.keys(eventData));\n\n // SES doesn't include email content in events by default\n // Check if content was somehow included\n if (eventData.content) {\n htmlBody = eventData.content.html;\n textBody = eventData.content.text;\n }\n\n // Check mail.content (unlikely but worth trying)\n if (eventData.mail?.content) {\n htmlBody = eventData.mail.content.html;\n textBody = eventData.mail.content.text;\n }\n } catch (e) {\n console.error(\"Failed to parse eventData:\", e);\n }\n }\n\n // Parse to addresses\n let toAddresses: string[] = [];\n const toField = sendEvent.to || sendEvent.destination;\n\n if (toField) {\n if (toField instanceof Set) {\n toAddresses = Array.from(toField);\n } else if (Array.isArray(toField)) {\n toAddresses = toField;\n } else if (typeof toField === \"string\") {\n toAddresses = [toField];\n }\n }\n\n // Determine final status (priority order: complaint > bounce > click > open > delivery > sent)\n let status: EmailDetails[\"status\"] = \"sent\";\n const hasDelivery = events.some(\n (e) => e.eventType?.toLowerCase() === \"delivery\"\n );\n const hasBounce = events.some(\n (e) => e.eventType?.toLowerCase() === \"bounce\"\n );\n const hasComplaint = events.some(\n (e) => e.eventType?.toLowerCase() === \"complaint\"\n );\n const hasOpen = events.some((e) => e.eventType?.toLowerCase() === \"open\");\n const hasClick = events.some((e) => e.eventType?.toLowerCase() === \"click\");\n\n if (hasComplaint) {\n status = \"complained\";\n } else if (hasBounce) {\n status = \"bounced\";\n } else if (hasClick) {\n status = \"clicked\";\n } else if (hasOpen) {\n status = \"opened\";\n } else if (hasDelivery) {\n status = \"delivered\";\n }\n\n // Map events to simplified timeline\n const timeline: EmailEvent[] = events\n .map((event) => {\n const eventType = event.eventType?.toLowerCase();\n let type: EmailEvent[\"type\"] = \"sent\";\n\n switch (eventType) {\n case \"send\":\n type = \"sent\";\n break;\n case \"delivery\":\n type = \"delivered\";\n break;\n case \"bounce\":\n type = \"bounced\";\n break;\n case \"complaint\":\n type = \"complained\";\n break;\n case \"open\":\n type = \"opened\";\n break;\n case \"click\":\n type = \"clicked\";\n break;\n default:\n type = \"sent\";\n }\n\n const metadata: Record<string, any> = {};\n\n // Add relevant metadata based on event type\n if (eventType === \"bounce\" && event.bounceType) {\n metadata.bounceType = event.bounceType;\n metadata.bounceSubType = event.bounceSubType;\n }\n\n if (eventType === \"complaint\" && event.complaintFeedbackType) {\n metadata.feedbackType = event.complaintFeedbackType;\n }\n\n if (eventType === \"click\" && event.link) {\n metadata.link = event.link;\n }\n\n if (event.userAgent) {\n metadata.userAgent = event.userAgent;\n }\n\n return {\n type,\n timestamp: Number(event.sentAt || event.timestamp),\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n };\n })\n .sort((a, b) => a.timestamp - b.timestamp);\n\n return {\n id: messageId,\n messageId,\n from: sendEvent.from || \"unknown\",\n to: toAddresses,\n replyTo: sendEvent.replyTo,\n subject: sendEvent.subject || \"(no subject)\",\n htmlBody: htmlBody || sendEvent.htmlBody,\n textBody: textBody || sendEvent.textBody,\n status,\n sentAt: Number(sendEvent.sentAt),\n events: timeline,\n };\n } catch (error) {\n console.error(\"Error fetching email by ID:\", error);\n throw error;\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { Request, Response, Router } from \"express\";\nimport { Router as createRouter } from \"express\";\nimport type { ServerConfig } from \"../server.js\";\nimport { fetchSESMetrics } from \"../services/aws-metrics.js\";\nimport { fetchSendQuota } from \"../services/ses-service.js\";\n\nexport function createMetricsRouter(config: ServerConfig): Router {\n const router = createRouter();\n\n /**\n * SSE endpoint for real-time metrics\n */\n router.get(\"/stream\", async (req: Request, res: Response) => {\n const connectionId = randomUUID().slice(0, 8);\n\n const log = (msg: string, data?: Record<string, unknown>) => {\n console.log(JSON.stringify({ connectionId, msg, ...data }));\n };\n\n // Set SSE headers\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n log(\"SSE connected\");\n\n // Send initial connection event\n res.write('data: {\"type\":\"connected\"}\\n\\n');\n\n // Get time range from query params, default to last 24 hours\n const { startTime, endTime } = req.query;\n const getTimeRange = () => ({\n start: startTime\n ? new Date(Number.parseInt(startTime as string, 10))\n : new Date(Date.now() - 24 * 60 * 60 * 1000),\n end: endTime\n ? new Date(Number.parseInt(endTime as string, 10))\n : new Date(),\n });\n\n // Function to fetch and send metrics\n const sendMetrics = async () => {\n try {\n const timeRange = getTimeRange();\n log(\"Fetching metrics\", {\n start: timeRange.start.toISOString(),\n end: timeRange.end.toISOString(),\n });\n\n const [metrics, quota] = await Promise.all([\n fetchSESMetrics(\n config.roleArn,\n config.region,\n timeRange,\n config.tableName\n ),\n fetchSendQuota(config.roleArn, config.region),\n ]);\n\n log(\"Metrics fetched successfully\");\n\n const data = {\n type: \"metrics\",\n timestamp: Date.now(),\n metrics,\n quota,\n };\n\n res.write(`data: ${JSON.stringify(data)}\\n\\n`);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\n JSON.stringify({\n connectionId,\n msg: \"Failed to fetch metrics\",\n error: errorMessage,\n })\n );\n res.write(\n `data: ${JSON.stringify({ type: \"error\", error: errorMessage })}\\n\\n`\n );\n }\n };\n\n // Send immediately on connect\n await sendMetrics();\n\n // Poll every 60 seconds\n const interval = setInterval(sendMetrics, 60_000);\n\n // Clean up on disconnect\n req.on(\"close\", () => {\n clearInterval(interval);\n log(\"SSE disconnected\");\n });\n });\n\n /**\n * Get current metrics snapshot (REST endpoint)\n */\n router.get(\"/snapshot\", async (_req: Request, res: Response) => {\n try {\n const timeRange = {\n start: new Date(Date.now() - 24 * 60 * 60 * 1000),\n end: new Date(),\n };\n\n const [metrics, quota] = await Promise.all([\n fetchSESMetrics(\n config.roleArn,\n config.region,\n timeRange,\n config.tableName\n ),\n fetchSendQuota(config.roleArn, config.region),\n ]);\n\n res.json({ metrics, quota });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Get metrics for a specific time range\n */\n router.get(\"/\", async (req: Request, res: Response) => {\n try {\n const { startTime, endTime } = req.query;\n\n // Default to last 24 hours if no time range provided\n const timeRange = {\n start: startTime\n ? new Date(Number.parseInt(startTime as string, 10))\n : new Date(Date.now() - 24 * 60 * 60 * 1000),\n end: endTime\n ? new Date(Number.parseInt(endTime as string, 10))\n : new Date(),\n };\n\n const [metrics, quota] = await Promise.all([\n fetchSESMetrics(\n config.roleArn,\n config.region,\n timeRange,\n config.tableName\n ),\n fetchSendQuota(config.roleArn, config.region),\n ]);\n\n res.json({\n metrics,\n quota,\n timestamp: Date.now(),\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\n JSON.stringify({ msg: \"Error fetching metrics\", error: errorMessage })\n );\n res.status(500).json({ error: errorMessage });\n }\n });\n\n return router;\n}\n","import {\n CloudWatchClient,\n GetMetricDataCommand,\n type MetricDataQuery,\n} from \"@aws-sdk/client-cloudwatch\";\nimport { assumeRole } from \"../../utils/shared/assume-role.js\";\n\nexport type MetricsData = {\n sends: Array<{ timestamp: number; value: number }>;\n bounces: Array<{ timestamp: number; value: number }>;\n complaints: Array<{ timestamp: number; value: number }>;\n deliveries: Array<{ timestamp: number; value: number }>;\n opens: Array<{ timestamp: number; value: number }>;\n clicks: Array<{ timestamp: number; value: number }>;\n};\n\n/**\n * Fetch SES metrics from CloudWatch\n */\nexport async function fetchSESMetrics(\n roleArn: string | undefined,\n region: string,\n timeRange: { start: Date; end: Date },\n tableName?: string\n): Promise<MetricsData> {\n // For console usage, use current credentials instead of assuming role\n const credentials = roleArn ? await assumeRole(roleArn, region) : undefined;\n\n // Create CloudWatch client\n const cloudwatch = new CloudWatchClient({ region, credentials });\n\n // Define metric queries\n const queries: MetricDataQuery[] = [\n {\n Id: \"sends\",\n MetricStat: {\n Metric: {\n Namespace: \"AWS/SES\",\n MetricName: \"Send\",\n },\n Period: 300, // 5 minutes\n Stat: \"Sum\",\n },\n },\n {\n Id: \"bounces\",\n MetricStat: {\n Metric: {\n Namespace: \"AWS/SES\",\n MetricName: \"Bounce\",\n },\n Period: 300,\n Stat: \"Sum\",\n },\n },\n {\n Id: \"complaints\",\n MetricStat: {\n Metric: {\n Namespace: \"AWS/SES\",\n MetricName: \"Complaint\",\n },\n Period: 300,\n Stat: \"Sum\",\n },\n },\n {\n Id: \"deliveries\",\n MetricStat: {\n Metric: {\n Namespace: \"AWS/SES\",\n MetricName: \"Delivery\",\n },\n Period: 300,\n Stat: \"Sum\",\n },\n },\n ];\n\n // Fetch metrics\n const response = await cloudwatch.send(\n new GetMetricDataCommand({\n MetricDataQueries: queries,\n StartTime: timeRange.start,\n EndTime: timeRange.end,\n })\n );\n\n // Parse results\n const results = response.MetricDataResults || [];\n\n const parseMetric = (id: string) => {\n const metric = results.find((r) => r.Id === id);\n if (!(metric?.Timestamps && metric.Values)) {\n return [];\n }\n\n return metric.Timestamps.map((timestamp, i) => ({\n timestamp: timestamp.getTime(),\n value: metric.Values?.[i] || 0,\n }));\n };\n\n // Fetch Opens and Clicks from DynamoDB if table name is provided\n let opens: Array<{ timestamp: number; value: number }> = [];\n let clicks: Array<{ timestamp: number; value: number }> = [];\n\n if (tableName) {\n try {\n const { fetchDynamoDBMetrics } = await import(\"./dynamodb-metrics.js\");\n const dynamoMetrics = await fetchDynamoDBMetrics(\n region,\n tableName,\n timeRange\n );\n opens = dynamoMetrics.opens;\n clicks = dynamoMetrics.clicks;\n } catch (error) {\n console.error(\"Error fetching DynamoDB metrics:\", error);\n // Continue with empty arrays\n }\n }\n\n return {\n sends: parseMetric(\"sends\"),\n bounces: parseMetric(\"bounces\"),\n complaints: parseMetric(\"complaints\"),\n deliveries: parseMetric(\"deliveries\"),\n opens,\n clicks,\n };\n}\n","import dns from \"node:dns/promises\";\nimport type { Request, Response, Router } from \"express\";\nimport { Router as createRouter } from \"express\";\nimport { loadConnectionMetadata } from \"../../utils/shared/metadata.js\";\nimport type { ServerConfig } from \"../server.js\";\nimport { fetchEmailSettings } from \"../services/settings-service.js\";\n\nexport function createSettingsRouter(config: ServerConfig): Router {\n const router = createRouter();\n\n /**\n * Get deployment configuration\n */\n router.get(\"/deployment\", async (_req: Request, res: Response) => {\n try {\n res.json({\n archivingEnabled: config.archivingEnabled ?? false,\n archiveArn: config.archiveArn,\n tableName: config.tableName,\n region: config.region,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching deployment config:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Get email settings (configuration set + identity)\n */\n router.get(\"/\", async (_req: Request, res: Response) => {\n try {\n // Load metadata to get configuration\n const metadata = await loadConnectionMetadata(\n config.accountId || \"\",\n config.region\n );\n\n if (!metadata) {\n return res.status(404).json({\n error: \"No Wraps infrastructure found for this account and region\",\n });\n }\n\n // Get configuration set name and domain from metadata\n const configSetName = \"wraps-email-tracking\"; // Always use this name\n const domain = metadata.services.email?.config.domain;\n\n // Fetch settings from AWS\n const settings = await fetchEmailSettings(\n config.roleArn,\n config.region,\n configSetName,\n domain\n );\n\n // Add region to response\n res.json({\n ...settings,\n region: config.region,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching settings:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Verify tracking domain CNAME\n */\n router.get(\"/verify-tracking-domain\", async (req: Request, res: Response) => {\n try {\n const { domain, expectedTarget } = req.query;\n\n if (!domain || typeof domain !== \"string\") {\n return res.status(400).json({ error: \"Domain parameter required\" });\n }\n\n if (!expectedTarget || typeof expectedTarget !== \"string\") {\n return res\n .status(400)\n .json({ error: \"Expected target parameter required\" });\n }\n\n console.log(`[Verify] Checking CNAME for: ${domain}`);\n console.log(`[Verify] Expected target: ${expectedTarget}`);\n\n // Check CNAME record using DNS\n const records = await dns.resolveCname(domain);\n\n console.log(\"[Verify] CNAME records found:\", records);\n\n // Check if any CNAME points to the expected target\n const verified = records.some((record) =>\n record.toLowerCase().includes(expectedTarget.toLowerCase())\n );\n\n console.log(`[Verify] Verified: ${verified}`);\n\n res.json({\n verified,\n error: verified\n ? undefined\n : `CNAME not pointing to ${expectedTarget}. Found: ${records.join(\", \")}`,\n });\n } catch (error: any) {\n console.error(\"[Verify] Error verifying tracking domain:\", error);\n\n // If no CNAME record exists, DNS will throw ENODATA or ENOTFOUND\n if (error.code === \"ENODATA\" || error.code === \"ENOTFOUND\") {\n return res.json({\n verified: false,\n error: \"No CNAME record found for this domain\",\n });\n }\n\n const errorMessage =\n error instanceof Error ? error.message : \"Failed to verify\";\n res.json({\n verified: false,\n error: errorMessage,\n });\n }\n });\n\n /**\n * Verify DMARC TXT record\n */\n router.get(\"/verify-dmarc\", async (req: Request, res: Response) => {\n try {\n const { domain } = req.query;\n\n if (!domain || typeof domain !== \"string\") {\n return res.status(400).json({ error: \"Domain parameter required\" });\n }\n\n const dmarcDomain = `_dmarc.${domain}`;\n\n console.log(`[Verify] Checking DMARC for: ${dmarcDomain}`);\n\n // Use Node.js DNS to resolve TXT records\n const records = await dns.resolveTxt(dmarcDomain);\n\n console.log(\"[Verify] TXT records found:\", records);\n\n // Check if there's a TXT record that starts with \"v=DMARC1\"\n // TXT records are arrays of strings, so we need to join them\n const hasDmarc = records.some((record) => {\n const value = record.join(\"\");\n return value.startsWith(\"v=DMARC1\");\n });\n\n console.log(`[Verify] DMARC verified: ${hasDmarc}`);\n\n res.json({\n verified: hasDmarc,\n error: hasDmarc ? undefined : \"DMARC record not found\",\n });\n } catch (error: any) {\n console.error(\"[Verify] Error verifying DMARC:\", error);\n\n // If no TXT record exists, DNS will throw ENODATA or ENOTFOUND\n if (error.code === \"ENODATA\" || error.code === \"ENOTFOUND\") {\n return res.json({\n verified: false,\n error: \"No DMARC record found for this domain\",\n });\n }\n\n const errorMessage =\n error instanceof Error ? error.message : \"Failed to verify\";\n res.json({\n verified: false,\n error: errorMessage,\n });\n }\n });\n\n /**\n * Update configuration set sending options\n */\n router.put(\"/config-set/sending\", async (req: Request, res: Response) => {\n try {\n const { enabled } = req.body;\n\n if (typeof enabled !== \"boolean\") {\n return res.status(400).json({ error: \"enabled must be a boolean\" });\n }\n\n // Load metadata to get configuration set name\n const metadata = await loadConnectionMetadata(\n config.accountId || \"\",\n config.region\n );\n\n if (!metadata) {\n return res.status(404).json({\n error: \"No Wraps infrastructure found for this account and region\",\n });\n }\n\n const configSetName = \"wraps-email-tracking\";\n\n console.log(\n `[Settings] Updating sending options for ${configSetName}: ${enabled}`\n );\n\n // Update sending options via AWS SDK\n const { SESv2Client, PutConfigurationSetSendingOptionsCommand } =\n await import(\"@aws-sdk/client-sesv2\");\n const { assumeRole } = await import(\"../../utils/shared/assume-role.js\");\n\n const credentials = config.roleArn\n ? await assumeRole(config.roleArn, config.region)\n : undefined;\n const sesClient = new SESv2Client({ region: config.region, credentials });\n\n await sesClient.send(\n new PutConfigurationSetSendingOptionsCommand({\n ConfigurationSetName: configSetName,\n SendingEnabled: enabled,\n })\n );\n\n console.log(\"[Settings] Successfully updated sending options\");\n\n res.json({ success: true });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"[Settings] Error updating sending options:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Update configuration set reputation options\n */\n router.put(\"/config-set/reputation\", async (req: Request, res: Response) => {\n try {\n const { enabled } = req.body;\n\n if (typeof enabled !== \"boolean\") {\n return res.status(400).json({ error: \"enabled must be a boolean\" });\n }\n\n // Load metadata to get configuration set name\n const metadata = await loadConnectionMetadata(\n config.accountId || \"\",\n config.region\n );\n\n if (!metadata) {\n return res.status(404).json({\n error: \"No Wraps infrastructure found for this account and region\",\n });\n }\n\n const configSetName = \"wraps-email-tracking\";\n\n console.log(\n `[Settings] Updating reputation options for ${configSetName}: ${enabled}`\n );\n\n // Update reputation options via AWS SDK\n const { SESv2Client, PutConfigurationSetReputationOptionsCommand } =\n await import(\"@aws-sdk/client-sesv2\");\n const { assumeRole } = await import(\"../../utils/shared/assume-role.js\");\n\n const credentials = config.roleArn\n ? await assumeRole(config.roleArn, config.region)\n : undefined;\n const sesClient = new SESv2Client({ region: config.region, credentials });\n\n await sesClient.send(\n new PutConfigurationSetReputationOptionsCommand({\n ConfigurationSetName: configSetName,\n ReputationMetricsEnabled: enabled,\n })\n );\n\n console.log(\"[Settings] Successfully updated reputation options\");\n\n res.json({ success: true });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"[Settings] Error updating reputation options:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Update tracking domain\n */\n router.put(\n \"/config-set/tracking-domain\",\n async (req: Request, res: Response) => {\n try {\n const { domain } = req.body;\n\n if (!domain || typeof domain !== \"string\") {\n return res.status(400).json({ error: \"domain must be a string\" });\n }\n\n // Validate domain format (basic check)\n const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-_.]+[a-zA-Z0-9]$/;\n if (!domainRegex.test(domain)) {\n return res.status(400).json({ error: \"Invalid domain format\" });\n }\n\n // Load metadata to get configuration set name\n const metadata = await loadConnectionMetadata(\n config.accountId || \"\",\n config.region\n );\n\n if (!metadata) {\n return res.status(404).json({\n error: \"No Wraps infrastructure found for this account and region\",\n });\n }\n\n const configSetName = \"wraps-email-tracking\";\n\n console.log(\n `[Settings] Updating tracking domain for ${configSetName}: ${domain}`\n );\n\n // Update tracking options via AWS SDK\n const { SESv2Client, PutConfigurationSetTrackingOptionsCommand } =\n await import(\"@aws-sdk/client-sesv2\");\n const { assumeRole } = await import(\n \"../../utils/shared/assume-role.js\"\n );\n\n const credentials = config.roleArn\n ? await assumeRole(config.roleArn, config.region)\n : undefined;\n const sesClient = new SESv2Client({\n region: config.region,\n credentials,\n });\n\n await sesClient.send(\n new PutConfigurationSetTrackingOptionsCommand({\n ConfigurationSetName: configSetName,\n CustomRedirectDomain: domain,\n })\n );\n\n console.log(\"[Settings] Successfully updated tracking domain\");\n\n res.json({ success: true });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"[Settings] Error updating tracking domain:\", error);\n res.status(500).json({ error: errorMessage });\n }\n }\n );\n\n return router;\n}\n","import {\n GetConfigurationSetCommand,\n GetEmailIdentityCommand,\n SESv2Client,\n} from \"@aws-sdk/client-sesv2\";\nimport { assumeRole } from \"../../utils/shared/assume-role.js\";\n\nexport type EmailSettings = {\n configurationSet?: ConfigurationSetDetails;\n identity?: EmailIdentityDetails;\n};\n\nexport type ConfigurationSetDetails = {\n name: string;\n trackingOptions?: {\n customRedirectDomain?: string;\n httpsPolicy?: \"REQUIRE\" | \"OPTIONAL\";\n };\n deliveryOptions?: {\n tlsPolicy?: \"REQUIRE\" | \"OPTIONAL\";\n sendingPoolName?: string;\n };\n reputationOptions?: {\n reputationMetricsEnabled: boolean;\n lastFreshStart?: Date;\n };\n sendingOptions?: {\n sendingEnabled: boolean;\n };\n suppressionOptions?: {\n suppressedReasons?: (\"BOUNCE\" | \"COMPLAINT\")[];\n };\n};\n\nexport type EmailIdentityDetails = {\n identityType: \"EMAIL_ADDRESS\" | \"DOMAIN\";\n identityName: string;\n verificationStatus:\n | \"PENDING\"\n | \"SUCCESS\"\n | \"FAILED\"\n | \"TEMPORARY_FAILURE\"\n | \"NOT_STARTED\";\n dkimAttributes?: {\n status: \"SUCCESS\" | \"PENDING\" | \"FAILED\" | \"NOT_STARTED\";\n tokens?: string[];\n signingEnabled: boolean;\n signingKeyLength?: \"RSA_1024_BIT\" | \"RSA_2048_BIT\";\n };\n mailFromAttributes?: {\n mailFromDomain?: string;\n mailFromDomainStatus?: \"PENDING\" | \"SUCCESS\" | \"FAILED\";\n behaviorOnMxFailure?: \"USE_DEFAULT_VALUE\" | \"REJECT_MESSAGE\";\n };\n configurationSetName?: string;\n verifiedForSendingStatus: boolean;\n tags?: Record<string, string>;\n};\n\n/**\n * Fetch configuration set details\n */\nexport async function fetchConfigurationSet(\n roleArn: string | undefined,\n region: string,\n configSetName: string\n): Promise<ConfigurationSetDetails> {\n const credentials = roleArn ? await assumeRole(roleArn, region) : undefined;\n const sesv2 = new SESv2Client({ region, credentials });\n\n const response = await sesv2.send(\n new GetConfigurationSetCommand({\n ConfigurationSetName: configSetName,\n })\n );\n\n return {\n name: configSetName,\n trackingOptions: response.TrackingOptions\n ? {\n customRedirectDomain: response.TrackingOptions.CustomRedirectDomain,\n httpsPolicy: response.TrackingOptions.HttpsPolicy as\n | \"REQUIRE\"\n | \"OPTIONAL\",\n }\n : undefined,\n deliveryOptions: response.DeliveryOptions\n ? {\n tlsPolicy: response.DeliveryOptions.TlsPolicy as\n | \"REQUIRE\"\n | \"OPTIONAL\",\n sendingPoolName: response.DeliveryOptions.SendingPoolName,\n }\n : undefined,\n reputationOptions: response.ReputationOptions\n ? {\n reputationMetricsEnabled:\n response.ReputationOptions.ReputationMetricsEnabled ?? false,\n lastFreshStart: response.ReputationOptions.LastFreshStart,\n }\n : undefined,\n sendingOptions: response.SendingOptions\n ? {\n sendingEnabled: response.SendingOptions.SendingEnabled ?? true,\n }\n : undefined,\n suppressionOptions: response.SuppressionOptions\n ? {\n suppressedReasons: response.SuppressionOptions.SuppressedReasons as\n | (\"BOUNCE\" | \"COMPLAINT\")[]\n | undefined,\n }\n : undefined,\n };\n}\n\n/**\n * Fetch email identity details\n */\nexport async function fetchEmailIdentity(\n roleArn: string | undefined,\n region: string,\n identityName: string\n): Promise<EmailIdentityDetails> {\n const credentials = roleArn ? await assumeRole(roleArn, region) : undefined;\n const sesv2 = new SESv2Client({ region, credentials });\n\n const response = await sesv2.send(\n new GetEmailIdentityCommand({\n EmailIdentity: identityName,\n })\n );\n\n return {\n identityType: response.IdentityType as \"EMAIL_ADDRESS\" | \"DOMAIN\",\n identityName,\n verificationStatus:\n response.VerificationStatus as EmailIdentityDetails[\"verificationStatus\"],\n dkimAttributes: response.DkimAttributes\n ? {\n status: response.DkimAttributes.Status as\n | \"SUCCESS\"\n | \"PENDING\"\n | \"FAILED\"\n | \"NOT_STARTED\",\n tokens: response.DkimAttributes.Tokens,\n signingEnabled: response.DkimAttributes.SigningEnabled ?? false,\n signingKeyLength: response.DkimAttributes\n .NextSigningKeyLength as NonNullable<\n EmailIdentityDetails[\"dkimAttributes\"]\n >[\"signingKeyLength\"],\n }\n : undefined,\n mailFromAttributes: response.MailFromAttributes\n ? {\n mailFromDomain: response.MailFromAttributes.MailFromDomain,\n mailFromDomainStatus: response.MailFromAttributes\n .MailFromDomainStatus as NonNullable<\n EmailIdentityDetails[\"mailFromAttributes\"]\n >[\"mailFromDomainStatus\"],\n behaviorOnMxFailure: response.MailFromAttributes\n .BehaviorOnMxFailure as NonNullable<\n EmailIdentityDetails[\"mailFromAttributes\"]\n >[\"behaviorOnMxFailure\"],\n }\n : undefined,\n configurationSetName: response.ConfigurationSetName,\n verifiedForSendingStatus: response.VerifiedForSendingStatus ?? false,\n tags: response.Tags?.reduce(\n (acc, tag) => {\n if (tag.Key) {\n acc[tag.Key] = tag.Value || \"\";\n }\n return acc;\n },\n {} as Record<string, string>\n ),\n };\n}\n\n/**\n * Fetch complete email settings\n */\nexport async function fetchEmailSettings(\n roleArn: string | undefined,\n region: string,\n configSetName?: string,\n domain?: string\n): Promise<EmailSettings> {\n const settings: EmailSettings = {};\n\n if (configSetName) {\n try {\n settings.configurationSet = await fetchConfigurationSet(\n roleArn,\n region,\n configSetName\n );\n } catch (error) {\n console.error(\"Failed to fetch configuration set:\", error);\n }\n }\n\n if (domain) {\n try {\n settings.identity = await fetchEmailIdentity(roleArn, region, domain);\n } catch (error) {\n console.error(\"Failed to fetch email identity:\", error);\n }\n }\n\n return settings;\n}\n","import type { Request, Response, Router } from \"express\";\nimport { Router as createRouter } from \"express\";\nimport type { ServerConfig } from \"../server.js\";\nimport { fetchSMSById, fetchSMSLogs } from \"../services/sms-logs.js\";\nimport {\n fetchSMSMetricsFromDynamoDB,\n fetchSMSSpendLimits,\n fetchSMSSummaryCounts,\n} from \"../services/sms-metrics.js\";\nimport {\n fetchAllSMSSettings,\n fetchPhoneNumberDetails,\n} from \"../services/sms-settings.js\";\n\nexport function createSMSRouter(config: ServerConfig): Router {\n const router = createRouter();\n\n /**\n * Get SMS logs\n */\n router.get(\"/\", async (req: Request, res: Response) => {\n try {\n console.log(\"SMS logs request received\");\n console.log(\"Query params:\", req.query);\n console.log(\"Config:\", {\n smsTableName: config.smsTableName,\n region: config.region,\n accountId: config.accountId,\n });\n\n const limit = req.query.limit\n ? Number.parseInt(req.query.limit as string, 10)\n : 100;\n const startTime = req.query.startTime\n ? Number.parseInt(req.query.startTime as string, 10)\n : undefined;\n const endTime = req.query.endTime\n ? Number.parseInt(req.query.endTime as string, 10)\n : undefined;\n\n if (!config.smsTableName) {\n console.log(\"No SMS table name configured\");\n return res.status(400).json({\n error:\n \"SMS tracking not enabled. Deploy SMS infrastructure with event tracking to enable SMS logs.\",\n });\n }\n\n console.log(\"Fetching SMS logs from DynamoDB...\");\n const logs = await fetchSMSLogs({\n region: config.region,\n tableName: config.smsTableName,\n accountId: config.accountId,\n limit,\n startTime,\n endTime,\n });\n\n console.log(`Found ${logs.length} SMS logs`);\n res.json({ logs });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching SMS logs:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Get SMS metrics\n * IMPORTANT: Must be defined BEFORE /:id route\n */\n router.get(\"/metrics\", async (req: Request, res: Response) => {\n try {\n console.log(\"SMS metrics request received\");\n\n const { startTime, endTime } = req.query;\n\n // Default to last 24 hours if no time range provided\n const timeRange = {\n start: startTime\n ? new Date(Number.parseInt(startTime as string, 10))\n : new Date(Date.now() - 24 * 60 * 60 * 1000),\n end: endTime\n ? new Date(Number.parseInt(endTime as string, 10))\n : new Date(),\n };\n\n // Fetch quota from AWS\n const quota = await fetchSMSSpendLimits(config.region);\n\n // Fetch metrics from DynamoDB if table is configured\n let metrics = {\n sends: [] as Array<{ timestamp: number; value: number }>,\n deliveries: [] as Array<{ timestamp: number; value: number }>,\n failures: [] as Array<{ timestamp: number; value: number }>,\n optOuts: [] as Array<{ timestamp: number; value: number }>,\n };\n\n let summary = {\n totalSent: 0,\n totalDelivered: 0,\n totalFailed: 0,\n deliveryRate: 0,\n };\n\n if (config.smsTableName) {\n [metrics, summary] = await Promise.all([\n fetchSMSMetricsFromDynamoDB(\n config.region,\n config.smsTableName,\n timeRange\n ),\n fetchSMSSummaryCounts(config.region, config.smsTableName, timeRange),\n ]);\n }\n\n // Fetch real phone number details from AWS\n let phoneNumberInfo;\n if (config.smsPhoneNumber || config.smsPhoneNumberArn) {\n const phoneDetails = await fetchPhoneNumberDetails(\n config.region,\n config.smsPhoneNumberArn || config.smsPhoneNumber!\n );\n if (phoneDetails) {\n phoneNumberInfo = {\n number: phoneDetails.number,\n type: phoneDetails.type,\n status: phoneDetails.status,\n throughput: phoneDetails.type === \"simulator\" ? \"100/day\" : \"3 MPS\",\n };\n }\n }\n\n const response = {\n metrics,\n summary,\n quota,\n phoneNumber: phoneNumberInfo,\n timestamp: Date.now(),\n };\n\n res.json(response);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching SMS metrics:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Get SMS settings\n * IMPORTANT: Must be defined BEFORE /:id route\n */\n router.get(\"/settings\", async (_req: Request, res: Response) => {\n try {\n console.log(\"SMS settings request received\");\n\n // Fetch real data from AWS\n const { phoneNumber: phoneDetails, configurationSet: configSetDetails } =\n await fetchAllSMSSettings(\n config.region,\n config.smsPhoneNumberArn || config.smsPhoneNumber,\n config.smsConfigSetName\n );\n\n // Build phone number info from real AWS data\n let phoneNumberInfo;\n if (phoneDetails) {\n phoneNumberInfo = {\n number: phoneDetails.number,\n arn: phoneDetails.arn,\n type: phoneDetails.type,\n status: phoneDetails.status,\n capabilities: phoneDetails.capabilities,\n registrationStatus: phoneDetails.registrationStatus,\n monthlyLeasingPrice: phoneDetails.monthlyLeasingPrice,\n };\n } else if (config.smsPhoneNumber) {\n // Fallback if AWS call fails\n phoneNumberInfo = {\n number: config.smsPhoneNumber,\n arn: config.smsPhoneNumberArn,\n type: config.smsPhoneNumberType || \"simulator\",\n status: \"UNKNOWN\",\n capabilities: [\"SMS\"],\n };\n }\n\n const settings = {\n phoneNumber: phoneNumberInfo,\n configurationSet: configSetDetails\n ? {\n name: configSetDetails.name,\n sendingEnabled: configSetDetails.sendingEnabled,\n defaultMessageType: configSetDetails.defaultMessageType,\n protectConfigurationId: configSetDetails.protectConfigurationId,\n }\n : config.smsConfigSetName\n ? {\n name: config.smsConfigSetName,\n sendingEnabled: true, // Fallback\n }\n : undefined,\n protectConfiguration: config.smsProtectEnabled\n ? {\n enabled: true,\n allowedCountries: config.smsAllowedCountries || [\"US\"],\n aitFiltering: config.smsAitFiltering,\n }\n : undefined,\n eventTracking: config.smsTableName\n ? {\n enabled: true,\n dynamoDBHistory: true,\n archiveRetention: config.smsArchiveRetention || \"90days\",\n }\n : {\n enabled: false,\n dynamoDBHistory: false,\n },\n region: config.region,\n };\n\n res.json(settings);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching SMS settings:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Update SMS sending enabled\n * IMPORTANT: Must be defined BEFORE /:id route\n */\n router.put(\"/settings/sending\", async (_req: Request, res: Response) => {\n try {\n console.log(\"SMS sending toggle request received\");\n // For now, just return success - actual implementation would need SDK calls\n res.json({ success: true });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error updating SMS sending:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n /**\n * Get SMS details by ID\n * IMPORTANT: Must be defined AFTER specific routes like /metrics and /settings\n */\n router.get(\"/:id\", async (req: Request, res: Response) => {\n try {\n const { id } = req.params;\n console.log(\"SMS detail request received for ID:\", id);\n\n if (!config.smsTableName) {\n console.log(\"No SMS table name configured\");\n return res.status(400).json({\n error:\n \"SMS tracking not enabled. Deploy SMS infrastructure with event tracking to enable SMS logs.\",\n });\n }\n\n console.log(\"Fetching SMS details from DynamoDB...\");\n const sms = await fetchSMSById(id, {\n region: config.region,\n tableName: config.smsTableName,\n });\n\n if (!sms) {\n console.log(\"SMS not found for ID:\", id);\n return res.status(404).json({ error: \"SMS not found\" });\n }\n\n console.log(\"SMS details found:\", sms.messageId);\n res.json(sms);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"Error fetching SMS details:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n return router;\n}\n","import {\n DynamoDBClient,\n QueryCommand,\n ScanCommand,\n} from \"@aws-sdk/client-dynamodb\";\nimport { unmarshall } from \"@aws-sdk/util-dynamodb\";\n\nexport type SMSLog = {\n messageId: string;\n to: string;\n from: string;\n body: string;\n status:\n | \"sent\"\n | \"delivered\"\n | \"failed\"\n | \"queued\"\n | \"blocked\"\n | \"invalid\"\n | \"opted_out\";\n sentAt: number;\n segments?: number;\n accountId?: string;\n errorMessage?: string;\n};\n\nexport type SMSEvent = {\n type:\n | \"sent\"\n | \"delivered\"\n | \"failed\"\n | \"queued\"\n | \"blocked\"\n | \"carrier_unreachable\"\n | \"invalid\"\n | \"opted_out\"\n | \"ttl_expired\";\n timestamp: number;\n metadata?: Record<string, any>;\n};\n\nexport type SMSDetails = {\n id: string;\n messageId: string;\n from: string;\n to: string;\n body: string;\n status:\n | \"sent\"\n | \"delivered\"\n | \"failed\"\n | \"queued\"\n | \"blocked\"\n | \"invalid\"\n | \"opted_out\";\n sentAt: number;\n segments: number;\n events: SMSEvent[];\n};\n\ntype FetchSMSLogsOptions = {\n region: string;\n tableName: string;\n accountId?: string;\n limit?: number;\n startTime?: number;\n endTime?: number;\n};\n\n/**\n * Fetch SMS logs from DynamoDB\n */\nexport async function fetchSMSLogs(\n options: FetchSMSLogsOptions\n): Promise<SMSLog[]> {\n const {\n region,\n tableName,\n accountId,\n limit = 100,\n startTime,\n endTime,\n } = options;\n\n const dynamodb = new DynamoDBClient({ region });\n\n try {\n let items: any[] = [];\n\n if (accountId) {\n let keyConditionExpression = \"accountId = :accountId\";\n const expressionAttributeValues: Record<string, any> = {\n \":accountId\": { S: accountId },\n };\n\n if (startTime && endTime) {\n keyConditionExpression += \" AND sentAt BETWEEN :startTime AND :endTime\";\n expressionAttributeValues[\":startTime\"] = { N: startTime.toString() };\n expressionAttributeValues[\":endTime\"] = { N: endTime.toString() };\n } else if (startTime) {\n keyConditionExpression += \" AND sentAt >= :startTime\";\n expressionAttributeValues[\":startTime\"] = { N: startTime.toString() };\n }\n\n const response = await dynamodb.send(\n new QueryCommand({\n TableName: tableName,\n IndexName: \"accountId-sentAt-index\",\n KeyConditionExpression: keyConditionExpression,\n ExpressionAttributeValues: expressionAttributeValues,\n ScanIndexForward: false,\n })\n );\n\n items = response.Items || [];\n } else {\n const response = await dynamodb.send(\n new ScanCommand({\n TableName: tableName,\n })\n );\n\n items = response.Items || [];\n }\n\n const unmarshalled = items.map((item) => unmarshall(item));\n\n // Group events by messageId to get the latest status for each SMS\n const smsMap = new Map<string, any>();\n\n for (const item of unmarshalled) {\n const messageId = item.messageId;\n const existing = smsMap.get(messageId);\n\n if (existing) {\n const currentPriority = getSMSEventPriority(item);\n const existingPriority = getSMSEventPriority(existing);\n\n if (currentPriority > existingPriority) {\n smsMap.set(messageId, item);\n }\n } else {\n smsMap.set(messageId, item);\n }\n }\n\n const logs = Array.from(smsMap.values())\n .map(normalizeSMSLog)\n .sort((a, b) => b.sentAt - a.sentAt);\n\n return logs.slice(0, limit);\n } catch (error) {\n console.error(\"Error fetching SMS logs:\", error);\n throw error;\n }\n}\n\n/**\n * Get priority for SMS event type (higher = more important)\n * AWS uses TEXT_* prefix for event types\n */\nfunction getSMSEventPriority(item: any): number {\n const type = item.eventType?.toUpperCase();\n\n // Handle AWS TEXT_* event types\n if (type?.includes(\"OPTED_OUT\")) return 8;\n if (type?.includes(\"BLOCKED\")) return 7;\n if (type?.includes(\"INVALID\")) return 6;\n if (type?.includes(\"FAILED\") || type?.includes(\"UNKNOWN\")) return 5;\n if (type?.includes(\"CARRIER_UNREACHABLE\") || type?.includes(\"UNREACHABLE\"))\n return 4;\n if (type?.includes(\"SUCCESSFUL\") || type?.includes(\"DELIVERED\")) return 3;\n if (type?.includes(\"SENT\") || type?.includes(\"PENDING\")) return 2;\n if (type?.includes(\"QUEUED\")) return 1;\n\n return 0;\n}\n\n/**\n * Normalize SMS log data from DynamoDB\n * AWS field names: destinationNumber, originationNumber, messageBody, eventType (TEXT_*)\n */\nfunction normalizeSMSLog(data: any): SMSLog {\n let status: SMSLog[\"status\"] = \"sent\";\n const eventType = data.eventType?.toUpperCase() || \"\";\n\n // AWS uses TEXT_* prefix for event types\n if (eventType.includes(\"SUCCESSFUL\") || eventType.includes(\"DELIVERED\")) {\n status = \"delivered\";\n } else if (\n eventType.includes(\"FAILED\") ||\n eventType.includes(\"UNREACHABLE\") ||\n eventType.includes(\"UNKNOWN\")\n ) {\n status = \"failed\";\n } else if (eventType.includes(\"QUEUED\") || eventType.includes(\"PENDING\")) {\n status = \"queued\";\n } else if (eventType.includes(\"BLOCKED\")) {\n status = \"blocked\";\n } else if (eventType.includes(\"INVALID\")) {\n status = \"invalid\";\n } else if (eventType.includes(\"OPTED_OUT\")) {\n status = \"opted_out\";\n } else if (eventType.includes(\"SENT\") || eventType.includes(\"TTL_EXPIRED\")) {\n status = \"sent\";\n } else if (data.errorMessage) {\n status = \"failed\";\n }\n\n // Clean phone numbers - remove leading single quote if present\n const cleanPhone = (phone: string | undefined): string => {\n if (!phone) return \"unknown\";\n return phone.replace(/^'+/, \"\");\n };\n\n return {\n messageId: data.messageId,\n to: cleanPhone(data.destinationNumber),\n from: cleanPhone(data.originationNumber),\n body: data.messageBody || \"(message content not stored)\",\n status,\n sentAt: Number(data.sentAt || data.timestamp),\n segments: Number(data.segments) || 1,\n accountId: data.accountId,\n errorMessage: data.errorMessage,\n };\n}\n\n/**\n * Fetch SMS details by message ID\n */\nexport async function fetchSMSById(\n messageId: string,\n options: { region: string; tableName: string }\n): Promise<SMSDetails | null> {\n const { region, tableName } = options;\n const dynamodb = new DynamoDBClient({ region });\n\n // Clean phone numbers - remove leading single quote if present\n const cleanPhone = (phone: string | undefined): string => {\n if (!phone) return \"unknown\";\n return phone.replace(/^'+/, \"\");\n };\n\n try {\n const response = await dynamodb.send(\n new QueryCommand({\n TableName: tableName,\n KeyConditionExpression: \"messageId = :messageId\",\n ExpressionAttributeValues: {\n \":messageId\": { S: messageId },\n },\n })\n );\n\n const items = response.Items || [];\n\n if (items.length === 0) {\n return null;\n }\n\n const events = items.map((item) => unmarshall(item));\n\n // Get the first event (all events for same messageId have same phone numbers)\n const primaryEvent = events[0];\n\n if (!primaryEvent) {\n return null;\n }\n\n // Determine final status based on event types\n // AWS uses TEXT_* prefix for event types\n let status: SMSDetails[\"status\"] = \"sent\";\n const hasDelivery = events.some((e) =>\n e.eventType?.toUpperCase().includes(\"SUCCESSFUL\")\n );\n const hasFailed = events.some(\n (e) =>\n e.eventType?.toUpperCase().includes(\"FAILED\") ||\n e.eventType?.toUpperCase().includes(\"UNREACHABLE\") ||\n e.eventType?.toUpperCase().includes(\"UNKNOWN\")\n );\n const hasBlocked = events.some((e) =>\n e.eventType?.toUpperCase().includes(\"BLOCKED\")\n );\n const hasInvalid = events.some((e) =>\n e.eventType?.toUpperCase().includes(\"INVALID\")\n );\n const hasOptedOut = events.some((e) =>\n e.eventType?.toUpperCase().includes(\"OPTED_OUT\")\n );\n\n if (hasOptedOut) {\n status = \"opted_out\";\n } else if (hasBlocked) {\n status = \"blocked\";\n } else if (hasInvalid) {\n status = \"invalid\";\n } else if (hasFailed) {\n status = \"failed\";\n } else if (hasDelivery) {\n status = \"delivered\";\n }\n\n // Map events to timeline\n const timeline: SMSEvent[] = events\n .map((event) => {\n const eventType = event.eventType?.toUpperCase() || \"\";\n let type: SMSEvent[\"type\"] = \"sent\";\n\n // Map AWS TEXT_* event types\n if (eventType.includes(\"SUCCESSFUL\")) {\n type = \"delivered\";\n } else if (eventType.includes(\"FAILED\")) {\n type = \"failed\";\n } else if (\n eventType.includes(\"PENDING\") ||\n eventType.includes(\"QUEUED\")\n ) {\n type = \"queued\";\n } else if (eventType.includes(\"BLOCKED\")) {\n type = \"blocked\";\n } else if (eventType.includes(\"UNREACHABLE\")) {\n type = \"carrier_unreachable\";\n } else if (eventType.includes(\"INVALID\")) {\n type = \"invalid\";\n } else if (eventType.includes(\"OPTED_OUT\")) {\n type = \"opted_out\";\n } else if (eventType.includes(\"TTL_EXPIRED\")) {\n type = \"ttl_expired\";\n }\n\n // Parse eventData JSON if present for additional metadata\n let eventData: Record<string, any> = {};\n if (event.eventData) {\n try {\n eventData =\n typeof event.eventData === \"string\"\n ? JSON.parse(event.eventData)\n : event.eventData;\n } catch (_e) {\n // Ignore parse errors\n }\n }\n\n const metadata: Record<string, any> = {};\n\n if (eventData.messageStatusDescription) {\n metadata.description = eventData.messageStatusDescription;\n }\n if (eventData.totalMessagePrice) {\n metadata.cost = `$${eventData.totalMessagePrice}`;\n }\n if (eventData.totalCarrierFee) {\n metadata.carrierFee = `$${eventData.totalCarrierFee}`;\n }\n if (eventData.messageEncoding) {\n metadata.encoding = eventData.messageEncoding;\n }\n if (event.errorMessage) {\n metadata.errorMessage = event.errorMessage;\n }\n\n return {\n type,\n timestamp: Number(event.sentAt || event.timestamp),\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n };\n })\n .sort((a, b) => a.timestamp - b.timestamp);\n\n return {\n id: messageId,\n messageId,\n from: cleanPhone(primaryEvent.originationNumber),\n to: cleanPhone(primaryEvent.destinationNumber),\n body: primaryEvent.messageBody || \"(message content not stored)\",\n status,\n sentAt: Number(primaryEvent.sentAt || primaryEvent.timestamp),\n segments: Number(primaryEvent.segments) || 1,\n events: timeline,\n };\n } catch (error) {\n console.error(\"Error fetching SMS by ID:\", error);\n throw error;\n }\n}\n","import {\n CloudWatchClient,\n GetMetricDataCommand,\n} from \"@aws-sdk/client-cloudwatch\";\nimport { DynamoDBClient, ScanCommand } from \"@aws-sdk/client-dynamodb\";\nimport {\n DescribeSpendLimitsCommand,\n PinpointSMSVoiceV2Client,\n} from \"@aws-sdk/client-pinpoint-sms-voice-v2\";\nimport { unmarshall } from \"@aws-sdk/util-dynamodb\";\n\nexport type SMSMetricsData = {\n sends: Array<{ timestamp: number; value: number }>;\n deliveries: Array<{ timestamp: number; value: number }>;\n failures: Array<{ timestamp: number; value: number }>;\n optOuts: Array<{ timestamp: number; value: number }>;\n};\n\nexport type SMSQuota = {\n spendLimitMonthly: number;\n spendLimitDaily: number;\n spentThisMonth: number;\n};\n\n/**\n * Fetch SMS spend limits and current spend from AWS\n */\nexport async function fetchSMSSpendLimits(region: string): Promise<SMSQuota> {\n const smsClient = new PinpointSMSVoiceV2Client({ region });\n const cloudwatch = new CloudWatchClient({ region });\n\n try {\n // Fetch spend limits from SMS API\n const spendLimits = await smsClient.send(\n new DescribeSpendLimitsCommand({})\n );\n\n // Find monthly limit\n let monthlyLimit = 1.0; // Default $1\n const dailyLimit = 1.0;\n\n for (const limit of spendLimits.SpendLimits || []) {\n if (limit.Name === \"TEXT_MESSAGE_MONTHLY_SPEND_LIMIT\") {\n monthlyLimit = limit.EnforcedLimit || limit.MaxLimit || 1.0;\n }\n }\n\n // Fetch current month's spend from CloudWatch\n // TextMessageMonthlySpend metric shows cumulative spend for the month\n const now = new Date();\n const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);\n\n const metricsResponse = await cloudwatch.send(\n new GetMetricDataCommand({\n MetricDataQueries: [\n {\n Id: \"monthlySpend\",\n MetricStat: {\n Metric: {\n Namespace: \"AWS/SMSVoice\",\n MetricName: \"TextMessageMonthlySpend\",\n },\n Period: 86_400, // 1 day\n Stat: \"Maximum\", // Get the latest cumulative value\n },\n },\n ],\n StartTime: startOfMonth,\n EndTime: now,\n ScanBy: \"TimestampDescending\", // Get most recent first\n })\n );\n\n let spentThisMonth = 0;\n const spendResults = metricsResponse.MetricDataResults?.find(\n (r) => r.Id === \"monthlySpend\"\n );\n if (spendResults?.Values && spendResults.Values.length > 0) {\n // Get the most recent (highest) value as it's cumulative\n spentThisMonth = Math.max(...spendResults.Values);\n }\n\n return {\n spendLimitMonthly: monthlyLimit,\n spendLimitDaily: dailyLimit,\n spentThisMonth,\n };\n } catch (error) {\n console.error(\"Error fetching SMS spend limits:\", error);\n // Return defaults if we can't fetch\n return {\n spendLimitMonthly: 1.0,\n spendLimitDaily: 1.0,\n spentThisMonth: 0,\n };\n }\n}\n\n/**\n * Fetch SMS metrics from DynamoDB (aggregated from event history)\n */\nexport async function fetchSMSMetricsFromDynamoDB(\n region: string,\n tableName: string,\n timeRange: { start: Date; end: Date }\n): Promise<SMSMetricsData> {\n const dynamodb = new DynamoDBClient({ region });\n\n try {\n // Scan for items in the time range\n // Note: For production with large datasets, this should use a GSI on timestamp\n const response = await dynamodb.send(\n new ScanCommand({\n TableName: tableName,\n FilterExpression: \"sentAt BETWEEN :start AND :end\",\n ExpressionAttributeValues: {\n \":start\": { N: timeRange.start.getTime().toString() },\n \":end\": { N: timeRange.end.getTime().toString() },\n },\n })\n );\n\n const items = (response.Items || []).map((item) => unmarshall(item));\n\n // Group by messageId to get unique messages (since we may have multiple events per message)\n const messageMap = new Map<string, any>();\n for (const item of items) {\n const messageId = item.messageId;\n const existing = messageMap.get(messageId);\n\n if (existing) {\n // Keep the item with highest priority event type\n const currentPriority = getEventPriority(item.eventType);\n const existingPriority = getEventPriority(existing.eventType);\n if (currentPriority > existingPriority) {\n messageMap.set(messageId, item);\n }\n } else {\n messageMap.set(messageId, item);\n }\n }\n\n // Aggregate by hour for the time series\n const hourlyBuckets = new Map<\n number,\n {\n sends: number;\n deliveries: number;\n failures: number;\n optOuts: number;\n }\n >();\n\n for (const item of messageMap.values()) {\n const timestamp = Number(item.sentAt || item.timestamp);\n // Round to hour\n const hourBucket =\n Math.floor(timestamp / (60 * 60 * 1000)) * (60 * 60 * 1000);\n\n const bucket = hourlyBuckets.get(hourBucket) || {\n sends: 0,\n deliveries: 0,\n failures: 0,\n optOuts: 0,\n };\n\n const eventType = (item.eventType || \"\").toUpperCase();\n\n // Count as a send regardless of final status\n bucket.sends++;\n\n if (eventType.includes(\"SUCCESSFUL\") || eventType.includes(\"DELIVERED\")) {\n bucket.deliveries++;\n } else if (\n eventType.includes(\"FAILED\") ||\n eventType.includes(\"UNREACHABLE\") ||\n eventType.includes(\"UNKNOWN\") ||\n eventType.includes(\"BLOCKED\") ||\n eventType.includes(\"INVALID\")\n ) {\n bucket.failures++;\n }\n\n if (eventType.includes(\"OPTED_OUT\")) {\n bucket.optOuts++;\n }\n\n hourlyBuckets.set(hourBucket, bucket);\n }\n\n // Convert to arrays\n const sortedBuckets = Array.from(hourlyBuckets.entries()).sort(\n ([a], [b]) => a - b\n );\n\n return {\n sends: sortedBuckets.map(([timestamp, data]) => ({\n timestamp,\n value: data.sends,\n })),\n deliveries: sortedBuckets.map(([timestamp, data]) => ({\n timestamp,\n value: data.deliveries,\n })),\n failures: sortedBuckets.map(([timestamp, data]) => ({\n timestamp,\n value: data.failures,\n })),\n optOuts: sortedBuckets.map(([timestamp, data]) => ({\n timestamp,\n value: data.optOuts,\n })),\n };\n } catch (error) {\n console.error(\"Error fetching SMS metrics from DynamoDB:\", error);\n return {\n sends: [],\n deliveries: [],\n failures: [],\n optOuts: [],\n };\n }\n}\n\n/**\n * Get event type priority (higher = more final)\n */\nfunction getEventPriority(eventType?: string): number {\n const type = (eventType || \"\").toUpperCase();\n if (type.includes(\"OPTED_OUT\")) return 8;\n if (type.includes(\"BLOCKED\")) return 7;\n if (type.includes(\"INVALID\")) return 6;\n if (type.includes(\"FAILED\") || type.includes(\"UNKNOWN\")) return 5;\n if (type.includes(\"UNREACHABLE\")) return 4;\n if (type.includes(\"SUCCESSFUL\") || type.includes(\"DELIVERED\")) return 3;\n if (type.includes(\"SENT\") || type.includes(\"PENDING\")) return 2;\n if (type.includes(\"QUEUED\")) return 1;\n return 0;\n}\n\n/**\n * Get summary counts from DynamoDB for dashboard stats\n */\nexport async function fetchSMSSummaryCounts(\n region: string,\n tableName: string,\n timeRange: { start: Date; end: Date }\n): Promise<{\n totalSent: number;\n totalDelivered: number;\n totalFailed: number;\n deliveryRate: number;\n}> {\n const metrics = await fetchSMSMetricsFromDynamoDB(\n region,\n tableName,\n timeRange\n );\n\n const totalSent = metrics.sends.reduce((sum, d) => sum + d.value, 0);\n const totalDelivered = metrics.deliveries.reduce(\n (sum, d) => sum + d.value,\n 0\n );\n const totalFailed = metrics.failures.reduce((sum, d) => sum + d.value, 0);\n const deliveryRate = totalSent > 0 ? (totalDelivered / totalSent) * 100 : 0;\n\n return {\n totalSent,\n totalDelivered,\n totalFailed,\n deliveryRate,\n };\n}\n","import {\n DescribeConfigurationSetsCommand,\n DescribePhoneNumbersCommand,\n PinpointSMSVoiceV2Client,\n} from \"@aws-sdk/client-pinpoint-sms-voice-v2\";\n\nexport type PhoneNumberDetails = {\n number: string;\n arn?: string;\n type: string;\n status: string;\n capabilities: string[];\n registrationStatus?: string;\n twoWayEnabled?: boolean;\n selfManagedOptOutsEnabled?: boolean;\n monthlyLeasingPrice?: string;\n};\n\nexport type ConfigurationSetDetails = {\n name: string;\n sendingEnabled: boolean;\n defaultMessageType?: string;\n defaultSenderId?: string;\n protectConfigurationId?: string;\n};\n\n/**\n * Fetch phone number details from AWS End User Messaging\n */\nexport async function fetchPhoneNumberDetails(\n region: string,\n phoneNumberOrArn: string\n): Promise<PhoneNumberDetails | null> {\n const client = new PinpointSMSVoiceV2Client({ region });\n\n try {\n // Query by phone number or ARN\n const response = await client.send(\n new DescribePhoneNumbersCommand({\n PhoneNumberIds: [phoneNumberOrArn],\n })\n );\n\n const phoneNumber = response.PhoneNumbers?.[0];\n if (!phoneNumber) {\n return null;\n }\n\n // Map AWS status to friendly status\n const mapStatus = (status?: string): string => {\n switch (status) {\n case \"PENDING\":\n return \"PENDING\";\n case \"ACTIVE\":\n return \"ACTIVE\";\n case \"ASSOCIATING\":\n return \"ASSOCIATING\";\n case \"DISASSOCIATING\":\n return \"DISASSOCIATING\";\n case \"DELETED\":\n return \"DELETED\";\n default:\n return status || \"UNKNOWN\";\n }\n };\n\n // Map number type\n const mapNumberType = (type?: string): string => {\n switch (type) {\n case \"SIMULATOR\":\n return \"simulator\";\n case \"TOLL_FREE\":\n return \"toll-free\";\n case \"TEN_DLC\":\n return \"10dlc\";\n case \"SHORT_CODE\":\n return \"short-code\";\n case \"LONG_CODE\":\n return \"long-code\";\n default:\n return type?.toLowerCase() || \"unknown\";\n }\n };\n\n // Map capabilities\n const capabilities: string[] = [];\n if (phoneNumber.NumberCapabilities) {\n for (const cap of phoneNumber.NumberCapabilities) {\n if (cap === \"SMS\") capabilities.push(\"SMS\");\n if (cap === \"VOICE\") capabilities.push(\"Voice\");\n if (cap === \"MMS\") capabilities.push(\"MMS\");\n }\n }\n\n // Get registration status for toll-free numbers\n let registrationStatus: string | undefined;\n if (phoneNumber.NumberType === \"TOLL_FREE\" && phoneNumber.RegistrationId) {\n registrationStatus = await fetchRegistrationStatus(\n client,\n phoneNumber.RegistrationId\n );\n }\n\n return {\n number: phoneNumber.PhoneNumber || phoneNumberOrArn,\n arn: phoneNumber.PhoneNumberArn,\n type: mapNumberType(phoneNumber.NumberType),\n status: mapStatus(phoneNumber.Status),\n capabilities,\n registrationStatus,\n twoWayEnabled: phoneNumber.TwoWayEnabled,\n selfManagedOptOutsEnabled: phoneNumber.SelfManagedOptOutsEnabled,\n monthlyLeasingPrice: phoneNumber.MonthlyLeasingPrice,\n };\n } catch (error) {\n console.error(\"Error fetching phone number details:\", error);\n return null;\n }\n}\n\n/**\n * Fetch registration status for toll-free verification\n */\nasync function fetchRegistrationStatus(\n client: PinpointSMSVoiceV2Client,\n registrationId: string\n): Promise<string | undefined> {\n try {\n // Use DescribeRegistrations to get the status\n const { DescribeRegistrationsCommand } = await import(\n \"@aws-sdk/client-pinpoint-sms-voice-v2\"\n );\n\n const response = await client.send(\n new DescribeRegistrationsCommand({\n RegistrationIds: [registrationId],\n })\n );\n\n const registration = response.Registrations?.[0];\n if (!registration) {\n return;\n }\n\n // Map registration status to friendly name\n const statusMap: Record<string, string> = {\n CREATED: \"CREATED\",\n SUBMITTED: \"SUBMITTED\",\n REVIEWING: \"REVIEWING\",\n PROVISIONING: \"PROVISIONING\",\n COMPLETE: \"VERIFIED\",\n REQUIRES_UPDATES: \"REQUIRES_UPDATES\",\n CLOSED: \"CLOSED\",\n DENIED: \"DENIED\",\n };\n\n const status = registration.RegistrationStatus;\n return status ? statusMap[status] || status : \"PENDING\";\n } catch (error) {\n console.error(\"Error fetching registration status:\", error);\n return \"PENDING_VERIFICATION\";\n }\n}\n\n/**\n * Fetch configuration set details from AWS End User Messaging\n */\nexport async function fetchConfigurationSetDetails(\n region: string,\n configSetName: string\n): Promise<ConfigurationSetDetails | null> {\n const client = new PinpointSMSVoiceV2Client({ region });\n\n try {\n const response = await client.send(\n new DescribeConfigurationSetsCommand({\n ConfigurationSetNames: [configSetName],\n })\n );\n\n const configSet = response.ConfigurationSets?.[0];\n if (!configSet) {\n return null;\n }\n\n return {\n name: configSet.ConfigurationSetName || configSetName,\n // If the config set exists and isn't deleted, sending is enabled\n // There's no explicit \"sending enabled\" flag - if it exists, it works\n sendingEnabled: true,\n defaultMessageType: configSet.DefaultMessageType,\n defaultSenderId: configSet.DefaultSenderId,\n protectConfigurationId: configSet.ProtectConfigurationId,\n };\n } catch (error) {\n console.error(\"Error fetching configuration set details:\", error);\n return null;\n }\n}\n\n/**\n * Fetch all SMS settings in one call\n */\nexport async function fetchAllSMSSettings(\n region: string,\n phoneNumberOrArn?: string,\n configSetName?: string\n): Promise<{\n phoneNumber: PhoneNumberDetails | null;\n configurationSet: ConfigurationSetDetails | null;\n}> {\n const [phoneNumber, configurationSet] = await Promise.all([\n phoneNumberOrArn\n ? fetchPhoneNumberDetails(region, phoneNumberOrArn)\n : Promise.resolve(null),\n configSetName\n ? fetchConfigurationSetDetails(region, configSetName)\n : Promise.resolve(null),\n ]);\n\n return { phoneNumber, configurationSet };\n}\n","import type { Request, Response, Router } from \"express\";\nimport { Router as createRouter } from \"express\";\nimport { loadConnectionMetadata } from \"../../utils/shared/metadata.js\";\nimport type { ServerConfig } from \"../server.js\";\n\nexport function createUserRouter(config: ServerConfig): Router {\n const router = createRouter();\n\n /**\n * Get current AWS user/account information\n */\n router.get(\"/\", async (_req: Request, res: Response) => {\n try {\n const accountId = config.accountId || \"Unknown\";\n const region = config.region;\n\n console.log(\n \"[User API] Fetching user info for account:\",\n accountId,\n \"region:\",\n region\n );\n\n // Load metadata to get additional details\n const metadata = await loadConnectionMetadata(accountId, region);\n console.log(\n \"[User API] Metadata loaded:\",\n metadata ? \"found\" : \"not found\"\n );\n\n // Get AWS account alias if available (for better UX)\n let accountAlias = accountId;\n try {\n if (config.roleArn) {\n console.log(\"[User API] Attempting to fetch account alias via IAM\");\n const { assumeRole } = await import(\n \"../../utils/shared/assume-role.js\"\n );\n const { IAMClient, ListAccountAliasesCommand } = await import(\n \"@aws-sdk/client-iam\"\n );\n\n const credentials = await assumeRole(config.roleArn, region);\n const iamClient = new IAMClient({ region, credentials });\n\n const response = await iamClient.send(\n new ListAccountAliasesCommand({})\n );\n\n if (response.AccountAliases && response.AccountAliases.length > 0) {\n accountAlias = response.AccountAliases[0];\n console.log(\"[User API] Account alias found:\", accountAlias);\n } else {\n console.log(\"[User API] No account alias found, using account ID\");\n }\n } else {\n console.log(\"[User API] No roleArn, skipping account alias lookup\");\n }\n } catch (error) {\n // Silently fail if we can't get account alias\n console.error(\"[User API] Error fetching account alias:\", error);\n }\n\n const responseData = {\n accountId,\n accountAlias,\n region,\n provider: metadata?.provider || \"unknown\",\n domain: metadata?.services?.email?.config?.domain || null,\n preset: metadata?.services?.email?.preset || null,\n timestamp: metadata?.timestamp || null,\n };\n\n console.log(\"[User API] Sending response:\", responseData);\n res.json(responseData);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n console.error(\"[User API] Error fetching user info:\", error);\n res.status(500).json({ error: errorMessage });\n }\n });\n\n return router;\n}\n","import * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport type { DestroyOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { loadConnectionMetadata } from \"../../utils/shared/metadata.js\";\nimport { emailDestroy } from \"../email/destroy.js\";\n\n/**\n * Global Destroy command - Show services and route to service-specific destroy\n */\nexport async function destroy(options: DestroyOptions): Promise<void> {\n clack.intro(pc.bold(\"Wraps Infrastructure Teardown\"));\n\n // 1. Validate AWS credentials\n const spinner = clack.spinner();\n spinner.start(\"Validating AWS credentials\");\n\n let identity;\n try {\n identity = await validateAWSCredentials();\n spinner.stop(\"AWS credentials validated\");\n } catch (error: any) {\n spinner.stop(\"AWS credentials validation failed\");\n throw error;\n }\n\n // 2. Get region\n const region = await getAWSRegion();\n\n // 3. Load connection metadata to see what services are deployed\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n\n const deployedServices: string[] = [];\n\n if (metadata?.services?.email) {\n deployedServices.push(\"email\");\n }\n\n if (deployedServices.length === 0) {\n clack.log.warn(\"No Wraps services found in this region\");\n console.log(\n `\\nRun ${pc.cyan(\"wraps email init\")} to deploy infrastructure.\\n`\n );\n process.exit(0);\n }\n\n // 4. If only one service, destroy it directly\n if (deployedServices.length === 1) {\n const service = deployedServices[0];\n clack.log.info(`Found ${pc.cyan(service)} service deployed`);\n\n if (service === \"email\") {\n // Pass through to email destroy\n await emailDestroy(options);\n return;\n }\n }\n\n // 5. Multiple services - ask which to destroy\n const serviceToDestroy = await clack.select({\n message: \"Which service would you like to destroy?\",\n options: [\n ...deployedServices.map((s) => ({\n value: s,\n label: s.charAt(0).toUpperCase() + s.slice(1),\n hint: s === \"email\" ? \"AWS SES email infrastructure\" : undefined,\n })),\n {\n value: \"all\",\n label: \"All services\",\n hint: \"Destroy all Wraps infrastructure\",\n },\n ],\n });\n\n if (clack.isCancel(serviceToDestroy)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n // 6. Route to appropriate destroy command\n if (\n (serviceToDestroy === \"email\" || serviceToDestroy === \"all\") &&\n deployedServices.includes(\"email\")\n ) {\n await emailDestroy(options);\n }\n\n if (serviceToDestroy === \"all\") {\n clack.outro(pc.green(\"All Wraps infrastructure has been removed\"));\n }\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { trackCommand } from \"../../telemetry/events.js\";\nimport type { StatusOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\n\n/**\n * Global Status command - Show overview of all deployed infrastructure\n */\nexport async function status(_options: StatusOptions): Promise<void> {\n const startTime = Date.now();\n const progress = new DeploymentProgress();\n\n clack.intro(pc.bold(\"Wraps Infrastructure Status\"));\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Loading infrastructure status\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`AWS Account: ${pc.cyan(identity.accountId)}`);\n\n // 2. Get region\n const region = await getAWSRegion();\n progress.info(`Region: ${pc.cyan(region)}`);\n\n // 3. Check for deployed services\n const services: Array<{\n name: string;\n status: \"deployed\" | \"not_deployed\";\n details?: string;\n }> = [];\n\n // Check Email infrastructure\n try {\n await ensurePulumiWorkDir();\n const emailStack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName: `wraps-${identity.accountId}-${region}`,\n workDir: getPulumiWorkDir(),\n });\n const emailOutputs = await emailStack.outputs();\n\n if (emailOutputs.roleArn?.value) {\n const domainCount = emailOutputs.domains?.value?.length || 0;\n services.push({\n name: \"Email\",\n status: \"deployed\",\n details: domainCount > 0 ? `${domainCount} domain(s)` : undefined,\n });\n } else {\n services.push({ name: \"Email\", status: \"not_deployed\" });\n }\n } catch (_error) {\n services.push({ name: \"Email\", status: \"not_deployed\" });\n }\n\n // Check SMS infrastructure\n try {\n const smsStack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName: `wraps-sms-${identity.accountId}-${region}`,\n workDir: getPulumiWorkDir(),\n });\n const smsOutputs = await smsStack.outputs();\n\n if (smsOutputs.roleArn?.value) {\n const phoneNumber = smsOutputs.phoneNumber?.value as string | undefined;\n services.push({\n name: \"SMS\",\n status: \"deployed\",\n details: phoneNumber || undefined,\n });\n } else {\n services.push({ name: \"SMS\", status: \"not_deployed\" });\n }\n } catch (_error) {\n services.push({ name: \"SMS\", status: \"not_deployed\" });\n }\n\n progress.stop();\n\n // 4. Display services overview\n console.log();\n clack.note(\n services\n .map((s) => {\n if (s.status === \"deployed\") {\n const details = s.details ? pc.dim(` (${s.details})`) : \"\";\n return ` ${pc.green(\"✓\")} ${s.name}${details}`;\n }\n return ` ${pc.dim(\"○\")} ${s.name} ${pc.dim(\"(not deployed)\")}`;\n })\n .join(\"\\n\"),\n \"Services\"\n );\n\n // 5. Show next steps\n const hasDeployedServices = services.some((s) => s.status === \"deployed\");\n\n if (hasDeployedServices) {\n console.log(`\\n${pc.bold(\"Details:\")}`);\n if (services.find((s) => s.name === \"Email\")?.status === \"deployed\") {\n console.log(` ${pc.dim(\"Email:\")} ${pc.cyan(\"wraps email status\")}`);\n }\n if (services.find((s) => s.name === \"SMS\")?.status === \"deployed\") {\n console.log(` ${pc.dim(\"SMS:\")} ${pc.cyan(\"wraps sms status\")}`);\n }\n } else {\n console.log(`\\n${pc.bold(\"Get started:\")}`);\n console.log(` ${pc.dim(\"Deploy email:\")} ${pc.cyan(\"wraps email init\")}`);\n console.log(` ${pc.dim(\"Deploy SMS:\")} ${pc.cyan(\"wraps sms init\")}`);\n }\n\n console.log(`\\n${pc.bold(\"Dashboard:\")} ${pc.blue(\"https://app.wraps.dev\")}`);\n console.log(`${pc.bold(\"Docs:\")} ${pc.blue(\"https://wraps.dev/docs\")}\\n`);\n\n // 6. Track status command\n trackCommand(\"status\", {\n success: true,\n services_deployed: services.filter((s) => s.status === \"deployed\").length,\n duration_ms: Date.now() - startTime,\n });\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport {\n deleteSMSEventDestinationWithSDK,\n deleteSMSPhonePoolWithSDK,\n deleteSMSProtectConfigurationWithSDK,\n} from \"../../infrastructure/sms-stack.js\";\nimport { trackError, trackServiceRemoved } from \"../../telemetry/events.js\";\nimport type { SMSDestroyOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { errors } from \"../../utils/shared/errors.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n loadConnectionMetadata,\n removeServiceFromConnection,\n saveConnectionMetadata,\n} from \"../../utils/shared/metadata.js\";\nimport {\n DeploymentProgress,\n displayPreview,\n} from \"../../utils/shared/output.js\";\n\n/**\n * SMS Destroy command - Remove SMS infrastructure\n */\nexport async function smsDestroy(options: SMSDestroyOptions): Promise<void> {\n const startTime = Date.now();\n\n clack.intro(\n pc.bold(\n options.preview\n ? \"SMS Infrastructure Destruction Preview\"\n : \"SMS Infrastructure Teardown\"\n )\n );\n\n const progress = new DeploymentProgress();\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region\n const region = await getAWSRegion();\n\n // 3. Load connection metadata to get stack name\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n const smsService = metadata?.services?.sms;\n const storedStackName = smsService?.pulumiStackName;\n\n if (!smsService) {\n progress.stop();\n clack.log.warn(\"No SMS infrastructure found\");\n process.exit(0);\n }\n\n // 4. Confirm destruction (skip if --force or --preview)\n if (!(options.force || options.preview)) {\n const confirmed = await clack.confirm({\n message: pc.red(\n \"Are you sure you want to destroy all SMS infrastructure?\"\n ),\n initialValue: false,\n });\n\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel(\"Destruction cancelled.\");\n process.exit(0);\n }\n }\n\n // 5. Preview or Destroy infrastructure using Pulumi\n if (options.preview) {\n // PREVIEW MODE - show what would be destroyed without actually destroying\n try {\n const previewResult = await progress.execute(\n \"Generating destruction preview\",\n async () => {\n await ensurePulumiWorkDir();\n\n // Use stored stack name from metadata, fallback to generated name\n const stackName =\n storedStackName || `wraps-sms-${identity.accountId}-${region}`;\n\n // Try to select the stack\n let stack;\n try {\n stack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName,\n workDir: getPulumiWorkDir(),\n });\n } catch (_error) {\n throw new Error(\"No SMS infrastructure found to preview\");\n }\n\n // Run preview to see what would be destroyed\n const result = await stack.preview({ diff: true });\n return result;\n }\n );\n\n // Display preview results\n displayPreview({\n changeSummary: previewResult.changeSummary,\n costEstimate: \"Monthly cost after destruction: $0.00\",\n commandName: \"wraps sms destroy\",\n });\n\n clack.outro(\n pc.green(\"Preview complete. Run without --preview to destroy.\")\n );\n\n // Track preview completion\n trackServiceRemoved(\"sms\", {\n preview: true,\n duration_ms: Date.now() - startTime,\n });\n return;\n } catch (error: unknown) {\n progress.stop();\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n\n if (errorMessage.includes(\"No SMS infrastructure found\")) {\n clack.log.warn(\"No SMS infrastructure found to preview\");\n process.exit(0);\n }\n trackError(\"PREVIEW_FAILED\", \"sms destroy\", { step: \"preview\" });\n throw new Error(`Preview failed: ${errorMessage}`);\n }\n }\n\n // DESTROY MODE - actually remove infrastructure\n\n // 6. Clean up SDK-created resources (phone pool and event destination)\n await progress.execute(\"Cleaning up phone pool\", async () => {\n await deleteSMSPhonePoolWithSDK(region);\n });\n\n if (smsService.config?.eventTracking?.enabled) {\n await progress.execute(\"Cleaning up event destination\", async () => {\n await deleteSMSEventDestinationWithSDK(\"wraps-sms-config\", region);\n });\n }\n\n // Clean up protect configuration\n await progress.execute(\"Cleaning up protect configuration\", async () => {\n await deleteSMSProtectConfigurationWithSDK(region);\n });\n\n // 7. Destroy Pulumi infrastructure\n try {\n await progress.execute(\n \"Destroying SMS infrastructure (this may take 2-3 minutes)\",\n async () => {\n await ensurePulumiWorkDir();\n\n // Use stored stack name from metadata, fallback to generated name\n const stackName =\n storedStackName || `wraps-sms-${identity.accountId}-${region}`;\n\n // Try to select the stack\n let stack;\n try {\n stack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName,\n workDir: getPulumiWorkDir(),\n });\n } catch (_error) {\n throw new Error(\"No SMS infrastructure found to destroy\");\n }\n\n // Run destroy\n await stack.destroy({ onOutput: () => {} }); // Suppress Pulumi output\n\n // Remove the stack from workspace\n await stack.workspace.removeStack(stackName);\n }\n );\n } catch (error: unknown) {\n progress.stop();\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (errorMessage.includes(\"No SMS infrastructure found\")) {\n clack.log.warn(\"No SMS infrastructure found\");\n // Still delete metadata if it exists\n if (metadata) {\n removeServiceFromConnection(metadata, \"sms\");\n await saveConnectionMetadata(metadata);\n }\n process.exit(0);\n }\n\n // Check if it's a lock file error\n if (errorMessage.includes(\"stack is currently locked\")) {\n trackError(\"STACK_LOCKED\", \"sms destroy\", { step: \"destroy\" });\n throw errors.stackLocked();\n }\n\n trackError(\"DESTROY_FAILED\", \"sms destroy\", { step: \"destroy\" });\n clack.log.error(\"SMS infrastructure destruction failed\");\n throw new Error(`SMS destruction failed: ${errorMessage}`);\n }\n\n // 7. Remove SMS service from connection metadata\n if (metadata) {\n removeServiceFromConnection(metadata, \"sms\");\n await saveConnectionMetadata(metadata);\n }\n\n // 8. Display success message\n progress.stop();\n\n clack.outro(pc.green(\"SMS infrastructure has been removed\"));\n\n console.log(`\\n${pc.bold(\"Cleaned up:\")}`);\n console.log(` ${pc.green(\"✓\")} Phone number released`);\n console.log(` ${pc.green(\"✓\")} Configuration set deleted`);\n console.log(` ${pc.green(\"✓\")} Event processing infrastructure removed`);\n console.log(` ${pc.green(\"✓\")} IAM role deleted`);\n\n console.log(\n `\\nRun ${pc.cyan(\"wraps sms init\")} to deploy infrastructure again.\\n`\n );\n\n // 9. Track successful destruction\n trackServiceRemoved(\"sms\", {\n reason: \"user_initiated\",\n duration_ms: Date.now() - startTime,\n });\n}\n","import * as aws from \"@pulumi/aws\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport type {\n Provider,\n SMSStackConfig,\n SMSStackOutputs,\n WrapsSMSConfig,\n} from \"../types/index.js\";\nimport { createVercelOIDC } from \"./vercel-oidc.js\";\n\n/**\n * Check if IAM role exists\n */\nasync function roleExists(roleName: string): Promise<boolean> {\n try {\n const { IAMClient, GetRoleCommand } = await import(\"@aws-sdk/client-iam\");\n const iam = new IAMClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n await iam.send(new GetRoleCommand({ RoleName: roleName }));\n return true;\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n \"name\" in error &&\n error.name === \"NoSuchEntityException\"\n ) {\n return false;\n }\n return false;\n }\n}\n\n/**\n * Check if DynamoDB table exists\n */\nasync function tableExists(tableName: string): Promise<boolean> {\n try {\n const { DynamoDBClient, DescribeTableCommand } = await import(\n \"@aws-sdk/client-dynamodb\"\n );\n const dynamodb = new DynamoDBClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n await dynamodb.send(new DescribeTableCommand({ TableName: tableName }));\n return true;\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n \"name\" in error &&\n error.name === \"ResourceNotFoundException\"\n ) {\n return false;\n }\n return false;\n }\n}\n\n/**\n * Create IAM role for SMS infrastructure\n */\nasync function createSMSIAMRole(config: {\n provider: Provider;\n oidcProvider?: aws.iam.OpenIdConnectProvider;\n vercelTeamSlug?: string;\n vercelProjectName?: string;\n smsConfig: WrapsSMSConfig;\n}): Promise<aws.iam.Role> {\n let assumeRolePolicy: pulumi.Output<string>;\n\n if (config.provider === \"vercel\" && config.oidcProvider) {\n // For Vercel, allow both OIDC (for SDK) and Lambda (for event processor)\n assumeRolePolicy = pulumi.interpolate`{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Federated\": \"${config.oidcProvider.arn}\"\n },\n \"Action\": \"sts:AssumeRoleWithWebIdentity\",\n \"Condition\": {\n \"StringEquals\": {\n \"oidc.vercel.com/${config.vercelTeamSlug}:aud\": \"https://vercel.com/${config.vercelTeamSlug}\"\n },\n \"StringLike\": {\n \"oidc.vercel.com/${config.vercelTeamSlug}:sub\": \"owner:${config.vercelTeamSlug}:project:${config.vercelProjectName}:environment:*\"\n }\n }\n },\n {\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Service\": \"lambda.amazonaws.com\"\n },\n \"Action\": \"sts:AssumeRole\"\n }\n ]\n }`;\n } else if (config.provider === \"aws\") {\n assumeRolePolicy = pulumi.output(`{\n \"Version\": \"2012-10-17\",\n \"Statement\": [{\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Service\": [\"lambda.amazonaws.com\", \"ec2.amazonaws.com\", \"ecs-tasks.amazonaws.com\"]\n },\n \"Action\": \"sts:AssumeRole\"\n }]\n }`);\n } else {\n throw new Error(\"Other providers not yet implemented\");\n }\n\n const roleName = \"wraps-sms-role\";\n const exists = await roleExists(roleName);\n\n const role = exists\n ? new aws.iam.Role(\n roleName,\n {\n name: roleName,\n assumeRolePolicy,\n tags: {\n ManagedBy: \"wraps-cli\",\n Service: \"sms\",\n Provider: config.provider,\n },\n },\n {\n import: roleName,\n customTimeouts: { create: \"2m\", update: \"2m\", delete: \"2m\" },\n }\n )\n : new aws.iam.Role(\n roleName,\n {\n name: roleName,\n assumeRolePolicy,\n tags: {\n ManagedBy: \"wraps-cli\",\n Service: \"sms\",\n Provider: config.provider,\n },\n },\n {\n customTimeouts: { create: \"2m\", update: \"2m\", delete: \"2m\" },\n }\n );\n\n // Build policy statements based on enabled features\n const statements: Record<string, unknown>[] = [];\n\n // Always allow reading SMS metrics\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"sms-voice:DescribeAccountAttributes\",\n \"sms-voice:DescribeSpendLimits\",\n \"sms-voice:DescribeConfigurationSets\",\n \"sms-voice:DescribeOptOutLists\",\n \"sms-voice:DescribePools\",\n \"sms-voice:DescribePhoneNumbers\",\n \"cloudwatch:GetMetricData\",\n \"cloudwatch:GetMetricStatistics\",\n ],\n Resource: \"*\",\n });\n\n // SMS sending permissions\n if (config.smsConfig.sendingEnabled !== false) {\n statements.push({\n Effect: \"Allow\",\n Action: [\"sms-voice:SendTextMessage\", \"sms-voice:SendMediaMessage\"],\n Resource: \"*\",\n });\n }\n\n // Opt-out management\n if (config.smsConfig.optOutManagement) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"sms-voice:PutOptedOutNumber\",\n \"sms-voice:DeleteOptedOutNumber\",\n \"sms-voice:DescribeOptedOutNumbers\",\n ],\n Resource: \"arn:aws:sms-voice:*:*:opt-out-list/wraps-sms-*\",\n });\n }\n\n // DynamoDB access for history\n if (config.smsConfig.eventTracking?.dynamoDBHistory) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"dynamodb:PutItem\",\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n \"dynamodb:Scan\",\n \"dynamodb:BatchGetItem\",\n \"dynamodb:DescribeTable\",\n ],\n Resource: [\n \"arn:aws:dynamodb:*:*:table/wraps-sms-*\",\n \"arn:aws:dynamodb:*:*:table/wraps-sms-*/index/*\",\n ],\n });\n }\n\n // SNS access for event publishing\n if (config.smsConfig.eventTracking?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\"sns:Publish\", \"sns:GetTopicAttributes\"],\n Resource: \"arn:aws:sns:*:*:wraps-sms-*\",\n });\n }\n\n // SQS access\n if (config.smsConfig.eventTracking?.enabled) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"sqs:SendMessage\",\n \"sqs:ReceiveMessage\",\n \"sqs:DeleteMessage\",\n \"sqs:GetQueueAttributes\",\n ],\n Resource: \"arn:aws:sqs:*:*:wraps-sms-*\",\n });\n }\n\n // Lambda permissions for event processor\n if (config.smsConfig.eventTracking?.dynamoDBHistory) {\n statements.push({\n Effect: \"Allow\",\n Action: [\n \"logs:CreateLogGroup\",\n \"logs:CreateLogStream\",\n \"logs:PutLogEvents\",\n ],\n Resource: \"arn:aws:logs:*:*:log-group:/aws/lambda/wraps-sms-*\",\n });\n }\n\n // Attach policy to role\n new aws.iam.RolePolicy(\"wraps-sms-policy\", {\n role: role.name,\n policy: JSON.stringify({\n Version: \"2012-10-17\",\n Statement: statements,\n }),\n });\n\n return role;\n}\n\n/**\n * Create SMS Configuration Set\n */\nfunction createSMSConfigurationSet(): aws.pinpoint.Smsvoicev2ConfigurationSet {\n return new aws.pinpoint.Smsvoicev2ConfigurationSet(\"wraps-sms-config\", {\n name: \"wraps-sms-config\",\n defaultMessageType: \"TRANSACTIONAL\",\n tags: {\n ManagedBy: \"wraps-cli\",\n Service: \"sms\",\n },\n });\n}\n\n/**\n * Create SMS Opt-Out List\n */\nfunction createSMSOptOutList(): aws.pinpoint.Smsvoicev2OptOutList {\n return new aws.pinpoint.Smsvoicev2OptOutList(\"wraps-sms-optouts\", {\n name: \"wraps-sms-optouts\",\n tags: {\n ManagedBy: \"wraps-cli\",\n Service: \"sms\",\n },\n });\n}\n\n/**\n * Check if a wraps-managed phone number already exists\n */\nasync function findExistingPhoneNumber(\n phoneNumberType: string\n): Promise<string | null> {\n try {\n const { PinpointSMSVoiceV2Client, DescribePhoneNumbersCommand } =\n await import(\"@aws-sdk/client-pinpoint-sms-voice-v2\");\n\n const client = new PinpointSMSVoiceV2Client({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n\n const numberTypeMap: Record<string, string> = {\n simulator: \"SIMULATOR\",\n \"toll-free\": \"TOLL_FREE\",\n \"10dlc\": \"TEN_DLC\",\n \"short-code\": \"SHORT_CODE\",\n };\n const targetType = numberTypeMap[phoneNumberType] || \"SIMULATOR\";\n\n const response = await client.send(new DescribePhoneNumbersCommand({}));\n\n // Find a phone number that matches our type and is managed by wraps\n for (const phone of response.PhoneNumbers || []) {\n if (phone.NumberType === targetType && phone.PhoneNumberArn) {\n // Check tags to see if it's managed by wraps\n const { ListTagsForResourceCommand } = await import(\n \"@aws-sdk/client-pinpoint-sms-voice-v2\"\n );\n const tagsResponse = await client.send(\n new ListTagsForResourceCommand({\n ResourceArn: phone.PhoneNumberArn,\n })\n );\n const isWrapsManaged = tagsResponse.Tags?.some(\n (t) => t.Key === \"ManagedBy\" && t.Value === \"wraps-cli\"\n );\n if (isWrapsManaged) {\n return phone.PhoneNumberArn;\n }\n }\n }\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Request a phone number\n */\nasync function createSMSPhoneNumber(\n phoneNumberType: string,\n optOutList: aws.pinpoint.Smsvoicev2OptOutList\n): Promise<aws.pinpoint.Smsvoicev2PhoneNumber> {\n // Map our phone number type to AWS number type\n const numberTypeMap: Record<string, string> = {\n simulator: \"SIMULATOR\",\n \"toll-free\": \"TOLL_FREE\",\n \"10dlc\": \"TEN_DLC\",\n \"short-code\": \"SHORT_CODE\",\n };\n\n // Check for existing phone number\n const existingArn = await findExistingPhoneNumber(phoneNumberType);\n\n const phoneConfig = {\n isoCountryCode: \"US\",\n messageType: \"TRANSACTIONAL\" as const,\n numberCapabilities: [\"SMS\"],\n numberType: numberTypeMap[phoneNumberType] || \"SIMULATOR\",\n optOutListName: optOutList.name,\n deletionProtectionEnabled: false,\n tags: {\n ManagedBy: \"wraps-cli\",\n Service: \"sms\",\n },\n };\n\n if (existingArn) {\n return new aws.pinpoint.Smsvoicev2PhoneNumber(\n \"wraps-sms-number\",\n phoneConfig,\n {\n import: existingArn,\n customTimeouts: { create: \"2m\", update: \"2m\", delete: \"2m\" },\n }\n );\n }\n\n return new aws.pinpoint.Smsvoicev2PhoneNumber(\n \"wraps-sms-number\",\n phoneConfig,\n {\n // Toll-free numbers stay in PENDING status until registration\n // Don't wait for ACTIVE status - return once provisioned\n customTimeouts: {\n create: \"2m\",\n update: \"2m\",\n delete: \"2m\",\n },\n }\n );\n}\n\n// Note: Phone pools are created via AWS SDK after Pulumi deployment\n// to avoid serialization issues with dynamic providers\n\n/**\n * Check if SQS queue exists\n */\nasync function sqsQueueExists(queueName: string): Promise<string | null> {\n try {\n const { SQSClient, GetQueueUrlCommand } = await import(\n \"@aws-sdk/client-sqs\"\n );\n const sqs = new SQSClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n const response = await sqs.send(\n new GetQueueUrlCommand({ QueueName: queueName })\n );\n return response.QueueUrl || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Create SQS queues for event processing\n */\nasync function createSMSSQSResources(): Promise<{\n queue: aws.sqs.Queue;\n dlq: aws.sqs.Queue;\n}> {\n const dlqName = \"wraps-sms-events-dlq\";\n const queueName = \"wraps-sms-events\";\n\n const dlqUrl = await sqsQueueExists(dlqName);\n const queueUrl = await sqsQueueExists(queueName);\n\n const dlqConfig = {\n name: dlqName,\n messageRetentionSeconds: 1_209_600, // 14 days\n tags: {\n ManagedBy: \"wraps-cli\",\n Service: \"sms\",\n Description: \"Dead letter queue for failed SMS event processing\",\n },\n };\n\n const dlq = dlqUrl\n ? new aws.sqs.Queue(dlqName, dlqConfig, {\n import: dlqUrl,\n customTimeouts: { create: \"2m\", update: \"2m\", delete: \"2m\" },\n })\n : new aws.sqs.Queue(dlqName, dlqConfig, {\n customTimeouts: { create: \"2m\", update: \"2m\", delete: \"2m\" },\n });\n\n const queueConfig = {\n name: queueName,\n visibilityTimeoutSeconds: 300, // 5 minutes\n messageRetentionSeconds: 345_600, // 4 days\n receiveWaitTimeSeconds: 20, // Long polling\n redrivePolicy: dlq.arn.apply((arn) =>\n JSON.stringify({\n deadLetterTargetArn: arn,\n maxReceiveCount: 3,\n })\n ),\n tags: {\n ManagedBy: \"wraps-cli\",\n Service: \"sms\",\n Description: \"Queue for SMS events from SNS\",\n },\n };\n\n const queue = queueUrl\n ? new aws.sqs.Queue(queueName, queueConfig, {\n import: queueUrl,\n customTimeouts: { create: \"2m\", update: \"2m\", delete: \"2m\" },\n })\n : new aws.sqs.Queue(queueName, queueConfig, {\n customTimeouts: { create: \"2m\", update: \"2m\", delete: \"2m\" },\n });\n\n return { queue, dlq };\n}\n\n/**\n * Check if SNS topic exists\n */\nasync function snsTopicExists(topicName: string): Promise<string | null> {\n try {\n const { SNSClient, ListTopicsCommand } = await import(\n \"@aws-sdk/client-sns\"\n );\n const sns = new SNSClient({\n region: process.env.AWS_REGION || \"us-east-1\",\n });\n let nextToken: string | undefined;\n\n do {\n const response = await sns.send(\n new ListTopicsCommand({ NextToken: nextToken })\n );\n const found = response.Topics?.find((t) =>\n t.TopicArn?.endsWith(`:${topicName}`)\n );\n if (found?.TopicArn) {\n return found.TopicArn;\n }\n nextToken = response.NextToken;\n } while (nextToken);\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Create SNS topic for SMS events\n * AWS End User Messaging sends events to SNS topics (not EventBridge)\n */\nasync function createSMSSNSResources(config: {\n queueArn: pulumi.Output<string>;\n queueUrl: pulumi.Output<string>;\n}): Promise<{\n topic: aws.sns.Topic;\n subscription: aws.sns.TopicSubscription;\n}> {\n const topicName = \"wraps-sms-events\";\n const topicArn = await snsTopicExists(topicName);\n\n const topicConfig = {\n name: topicName,\n tags: {\n ManagedBy: \"wraps-cli\",\n Service: \"sms\",\n Description: \"SNS topic for SMS delivery events\",\n },\n };\n\n // SNS topic for SMS events\n const topic = topicArn\n ? new aws.sns.Topic(\"wraps-sms-events-topic\", topicConfig, {\n import: topicArn,\n customTimeouts: { create: \"2m\", update: \"2m\", delete: \"2m\" },\n })\n : new aws.sns.Topic(\"wraps-sms-events-topic\", topicConfig, {\n customTimeouts: { create: \"2m\", update: \"2m\", delete: \"2m\" },\n });\n\n // SNS topic policy to allow SMS service to publish events\n new aws.sns.TopicPolicy(\"wraps-sms-events-topic-policy\", {\n arn: topic.arn,\n policy: topic.arn.apply((topicArn) =>\n JSON.stringify({\n Version: \"2012-10-17\",\n Statement: [\n {\n Sid: \"AllowSMSServicePublish\",\n Effect: \"Allow\",\n Principal: { Service: \"sms-voice.amazonaws.com\" },\n Action: \"sns:Publish\",\n Resource: topicArn,\n },\n ],\n })\n ),\n });\n\n // SQS queue policy to allow SNS to send messages\n new aws.sqs.QueuePolicy(\"wraps-sms-events-queue-policy\", {\n queueUrl: config.queueUrl,\n policy: pulumi\n .all([config.queueArn, topic.arn])\n .apply(([queueArn, topicArn]) =>\n JSON.stringify({\n Version: \"2012-10-17\",\n Statement: [\n {\n Effect: \"Allow\",\n Principal: { Service: \"sns.amazonaws.com\" },\n Action: \"sqs:SendMessage\",\n Resource: queueArn,\n Condition: {\n ArnEquals: { \"aws:SourceArn\": topicArn },\n },\n },\n ],\n })\n ),\n });\n\n // Subscribe SQS queue to SNS topic\n const subscription = new aws.sns.TopicSubscription(\n \"wraps-sms-events-subscription\",\n {\n topic: topic.arn,\n protocol: \"sqs\",\n endpoint: config.queueArn,\n rawMessageDelivery: true, // Deliver raw message without SNS envelope\n }\n );\n\n return { topic, subscription };\n}\n\n// Note: Event destinations are created via AWS SDK after Pulumi deployment\n// to avoid serialization issues with dynamic providers\n\n/**\n * Create DynamoDB table for SMS history\n */\nasync function createSMSDynamoDBTable(): Promise<aws.dynamodb.Table> {\n const tableName = \"wraps-sms-history\";\n const exists = await tableExists(tableName);\n\n const tableConfig = {\n name: tableName,\n billingMode: \"PAY_PER_REQUEST\" as const,\n hashKey: \"messageId\",\n rangeKey: \"sentAt\",\n attributes: [\n { name: \"messageId\", type: \"S\" as const },\n { name: \"sentAt\", type: \"N\" as const },\n { name: \"accountId\", type: \"S\" as const },\n { name: \"destinationNumber\", type: \"S\" as const },\n ],\n globalSecondaryIndexes: [\n {\n name: \"accountId-sentAt-index\",\n hashKey: \"accountId\",\n rangeKey: \"sentAt\",\n projectionType: \"ALL\" as const,\n },\n {\n name: \"destinationNumber-sentAt-index\",\n hashKey: \"destinationNumber\",\n rangeKey: \"sentAt\",\n projectionType: \"ALL\" as const,\n },\n ],\n ttl: {\n enabled: true,\n attributeName: \"expiresAt\",\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n Service: \"sms\",\n },\n };\n\n return exists\n ? new aws.dynamodb.Table(tableName, tableConfig, {\n import: tableName,\n customTimeouts: { create: \"5m\", update: \"5m\", delete: \"5m\" },\n })\n : new aws.dynamodb.Table(tableName, tableConfig, {\n customTimeouts: { create: \"5m\", update: \"5m\", delete: \"5m\" },\n });\n}\n\n/**\n * Deploy Lambda event processor\n */\nasync function deploySMSLambdaFunction(config: {\n tableName: pulumi.Output<string>;\n queueArn: pulumi.Output<string>;\n accountId: string;\n region: string;\n}): Promise<aws.lambda.Function> {\n // Bundle Lambda code\n const { getLambdaCode } = await import(\"./resources/lambda.js\");\n const codeDir = await getLambdaCode(\"sms-event-processor\");\n\n // Create dedicated Lambda execution role (like email stack does)\n const lambdaRole = new aws.iam.Role(\"wraps-sms-lambda-role\", {\n name: \"wraps-sms-lambda-role\",\n assumeRolePolicy: JSON.stringify({\n Version: \"2012-10-17\",\n Statement: [\n {\n Effect: \"Allow\",\n Principal: { Service: \"lambda.amazonaws.com\" },\n Action: \"sts:AssumeRole\",\n },\n ],\n }),\n tags: {\n ManagedBy: \"wraps-cli\",\n Service: \"sms\",\n },\n });\n\n // Attach basic Lambda execution policy (CloudWatch Logs)\n new aws.iam.RolePolicyAttachment(\"wraps-sms-lambda-basic-execution\", {\n role: lambdaRole.name,\n policyArn:\n \"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole\",\n });\n\n // Lambda policy for DynamoDB and SQS\n new aws.iam.RolePolicy(\"wraps-sms-lambda-policy\", {\n role: lambdaRole.name,\n policy: pulumi\n .all([config.tableName, config.queueArn])\n .apply(([tableName, queueArn]) =>\n JSON.stringify({\n Version: \"2012-10-17\",\n Statement: [\n {\n Effect: \"Allow\",\n Action: [\n \"dynamodb:PutItem\",\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n \"dynamodb:UpdateItem\",\n ],\n Resource: [\n `arn:aws:dynamodb:*:*:table/${tableName}`,\n `arn:aws:dynamodb:*:*:table/${tableName}/index/*`,\n ],\n },\n {\n Effect: \"Allow\",\n Action: [\n \"sqs:ReceiveMessage\",\n \"sqs:DeleteMessage\",\n \"sqs:GetQueueAttributes\",\n ],\n Resource: queueArn,\n },\n ],\n })\n ),\n });\n\n // Create Lambda function\n const eventProcessor = new aws.lambda.Function(\n \"wraps-sms-event-processor\",\n {\n name: \"wraps-sms-event-processor\",\n runtime: \"nodejs20.x\",\n handler: \"index.handler\",\n role: lambdaRole.arn,\n code: new pulumi.asset.FileArchive(codeDir),\n timeout: 300, // 5 minutes\n memorySize: 512,\n environment: {\n variables: {\n TABLE_NAME: config.tableName,\n AWS_ACCOUNT_ID: config.accountId,\n },\n },\n tags: {\n ManagedBy: \"wraps-cli\",\n Service: \"sms\",\n },\n },\n {\n dependsOn: [lambdaRole],\n customTimeouts: { create: \"5m\", update: \"5m\", delete: \"2m\" },\n }\n );\n\n // Create event source mapping from SQS\n new aws.lambda.EventSourceMapping(\n \"wraps-sms-event-source-mapping\",\n {\n eventSourceArn: config.queueArn,\n functionName: eventProcessor.name,\n batchSize: 10,\n maximumBatchingWindowInSeconds: 5,\n functionResponseTypes: [\"ReportBatchItemFailures\"],\n },\n {\n customTimeouts: { create: \"2m\", update: \"2m\", delete: \"2m\" },\n }\n );\n\n return eventProcessor;\n}\n\n/**\n * Deploy SMS infrastructure stack using Pulumi\n */\nexport async function deploySMSStack(\n config: SMSStackConfig\n): Promise<SMSStackOutputs> {\n // Get current AWS account\n const identity = await aws.getCallerIdentity();\n const accountId = identity.accountId;\n\n let oidcProvider: aws.iam.OpenIdConnectProvider | undefined;\n\n // 1. Create OIDC provider if Vercel\n if (config.provider === \"vercel\" && config.vercel) {\n oidcProvider = await createVercelOIDC({\n teamSlug: config.vercel.teamSlug,\n accountId,\n });\n }\n\n const smsConfig = config.smsConfig;\n\n // 2. Create IAM role\n const role = await createSMSIAMRole({\n provider: config.provider,\n oidcProvider,\n vercelTeamSlug: config.vercel?.teamSlug,\n vercelProjectName: config.vercel?.projectName,\n smsConfig,\n });\n\n // 3. Create opt-out list\n const optOutList = createSMSOptOutList();\n\n // 4. Create configuration set\n const configSet = createSMSConfigurationSet();\n\n // 5. Create phone number (if phone number type is specified)\n let phoneNumber: aws.pinpoint.Smsvoicev2PhoneNumber | undefined;\n if (smsConfig.phoneNumberType) {\n phoneNumber = await createSMSPhoneNumber(\n smsConfig.phoneNumberType,\n optOutList\n );\n // Note: Phone pool is created via AWS SDK after Pulumi deployment\n }\n\n // 6. Create SQS queues (if event tracking enabled)\n let sqsResources;\n if (smsConfig.eventTracking?.enabled) {\n sqsResources = await createSMSSQSResources();\n }\n\n // 7. Create SNS topic (if event tracking enabled)\n let snsResources;\n if (smsConfig.eventTracking?.enabled && sqsResources) {\n snsResources = await createSMSSNSResources({\n queueArn: sqsResources.queue.arn,\n queueUrl: sqsResources.queue.url,\n });\n // Note: Event destination is created via AWS SDK after Pulumi deployment\n }\n\n // 8. Create DynamoDB table (if history storage enabled)\n let dynamoTable;\n if (smsConfig.eventTracking?.dynamoDBHistory) {\n dynamoTable = await createSMSDynamoDBTable();\n }\n\n // 9. Deploy Lambda function (if event tracking + DynamoDB enabled)\n let lambdaFunction;\n if (smsConfig.eventTracking?.dynamoDBHistory && dynamoTable && sqsResources) {\n lambdaFunction = await deploySMSLambdaFunction({\n tableName: dynamoTable.name,\n queueArn: sqsResources.queue.arn,\n accountId,\n region: config.region,\n });\n }\n\n // Return outputs\n return {\n roleArn: role.arn as unknown as string,\n phoneNumber: phoneNumber?.phoneNumber as unknown as string | undefined,\n phoneNumberArn: phoneNumber?.arn as unknown as string | undefined,\n phoneNumberType: smsConfig.phoneNumberType || \"simulator\",\n configSetName: configSet.name as unknown as string | undefined,\n tableName: dynamoTable?.name as unknown as string | undefined,\n region: config.region,\n lambdaFunctions: lambdaFunction\n ? [lambdaFunction.arn as unknown as string]\n : undefined,\n snsTopicArn: snsResources?.topic.arn as unknown as string | undefined,\n queueUrl: sqsResources?.queue.url as unknown as string | undefined,\n dlqUrl: sqsResources?.dlq.url as unknown as string | undefined,\n optOutListArn: optOutList.arn as unknown as string | undefined,\n };\n}\n\n/**\n * Create SMS Phone Pool using AWS SDK (called after Pulumi deployment)\n * This is separate from Pulumi to avoid dynamic provider serialization issues\n */\nexport async function createSMSPhonePoolWithSDK(\n phoneNumberArn: string,\n region: string\n): Promise<string | undefined> {\n const { PinpointSMSVoiceV2Client, CreatePoolCommand, DescribePoolsCommand } =\n await import(\"@aws-sdk/client-pinpoint-sms-voice-v2\");\n\n const client = new PinpointSMSVoiceV2Client({ region });\n\n // Check if pool already exists by listing all pools\n try {\n const existing = await client.send(new DescribePoolsCommand({}));\n if (existing.Pools && existing.Pools.length > 0) {\n // Find pool that contains this phone number\n for (const pool of existing.Pools) {\n if (pool.PoolId) {\n return pool.PoolId;\n }\n }\n }\n } catch {\n // Pool doesn't exist, create it\n }\n\n try {\n const response = await client.send(\n new CreatePoolCommand({\n OriginationIdentity: phoneNumberArn,\n IsoCountryCode: \"US\",\n MessageType: \"TRANSACTIONAL\",\n DeletionProtectionEnabled: false,\n Tags: [\n { Key: \"ManagedBy\", Value: \"wraps-cli\" },\n { Key: \"Service\", Value: \"sms\" },\n ],\n })\n );\n return response.PoolId;\n } catch {\n // Pool may already exist, phone number pending, or other error\n return;\n }\n}\n\n/**\n * Create SMS Event Destination using AWS SDK (called after Pulumi deployment)\n * This is separate from Pulumi to avoid dynamic provider serialization issues\n */\nexport async function createSMSEventDestinationWithSDK(\n configurationSetName: string,\n snsTopicArn: string,\n region: string\n): Promise<string | undefined> {\n const {\n PinpointSMSVoiceV2Client,\n CreateEventDestinationCommand,\n DescribeConfigurationSetsCommand,\n } = await import(\"@aws-sdk/client-pinpoint-sms-voice-v2\");\n\n const client = new PinpointSMSVoiceV2Client({ region });\n const eventDestinationName = \"wraps-sms-sns-destination\";\n\n // Check if event destination already exists\n try {\n const existing = await client.send(\n new DescribeConfigurationSetsCommand({\n ConfigurationSetNames: [configurationSetName],\n })\n );\n const configSet = existing.ConfigurationSets?.[0];\n if (configSet?.EventDestinations) {\n const existingDest = configSet.EventDestinations.find(\n (d) => d.EventDestinationName === eventDestinationName\n );\n if (existingDest) {\n return existingDest.EventDestinationName;\n }\n }\n } catch {\n // Config set may not exist yet\n }\n\n try {\n const response = await client.send(\n new CreateEventDestinationCommand({\n ConfigurationSetName: configurationSetName,\n EventDestinationName: eventDestinationName,\n MatchingEventTypes: [\"ALL\"],\n SnsDestination: {\n TopicArn: snsTopicArn,\n },\n })\n );\n return (\n response.EventDestination?.EventDestinationName || eventDestinationName\n );\n } catch {\n // Event destination may already exist\n return eventDestinationName;\n }\n}\n\n/**\n * Delete SMS Phone Pool using AWS SDK (called before Pulumi destroy)\n */\nexport async function deleteSMSPhonePoolWithSDK(region: string): Promise<void> {\n const {\n PinpointSMSVoiceV2Client,\n DeletePoolCommand,\n DescribePoolsCommand,\n ListTagsForResourceCommand,\n } = await import(\"@aws-sdk/client-pinpoint-sms-voice-v2\");\n\n const client = new PinpointSMSVoiceV2Client({ region });\n\n try {\n // Find all pools and check their tags\n const existing = await client.send(new DescribePoolsCommand({}));\n if (existing.Pools) {\n for (const pool of existing.Pools) {\n if (!(pool.PoolArn && pool.PoolId)) continue;\n\n // Get tags for this pool\n const tagsResponse = await client.send(\n new ListTagsForResourceCommand({ ResourceArn: pool.PoolArn })\n );\n\n // Check if this pool is managed by wraps-cli\n const isWrapsPool = tagsResponse.Tags?.some(\n (t) => t.Key === \"ManagedBy\" && t.Value === \"wraps-cli\"\n );\n\n if (isWrapsPool) {\n await client.send(new DeletePoolCommand({ PoolId: pool.PoolId }));\n }\n }\n }\n } catch {\n // Pool may not exist\n }\n}\n\n/**\n * Delete SMS Event Destination using AWS SDK (called before Pulumi destroy)\n */\nexport async function deleteSMSEventDestinationWithSDK(\n configurationSetName: string,\n region: string\n): Promise<void> {\n const { PinpointSMSVoiceV2Client, DeleteEventDestinationCommand } =\n await import(\"@aws-sdk/client-pinpoint-sms-voice-v2\");\n\n const client = new PinpointSMSVoiceV2Client({ region });\n const eventDestinationName = \"wraps-sms-sns-destination\";\n\n try {\n await client.send(\n new DeleteEventDestinationCommand({\n ConfigurationSetName: configurationSetName,\n EventDestinationName: eventDestinationName,\n })\n );\n } catch {\n // Event destination may not exist\n }\n}\n\n/**\n * Create SMS Protect Configuration using AWS SDK\n * Configures country-specific messaging controls to prevent SMS pumping fraud\n */\nexport async function createSMSProtectConfigurationWithSDK(\n configurationSetName: string,\n region: string,\n options?: {\n allowedCountries?: string[];\n aitFiltering?: boolean;\n }\n): Promise<string | undefined> {\n const {\n PinpointSMSVoiceV2Client,\n CreateProtectConfigurationCommand,\n UpdateProtectConfigurationCountryRuleSetCommand,\n AssociateProtectConfigurationCommand,\n DescribeProtectConfigurationsCommand,\n GetProtectConfigurationCountryRuleSetCommand,\n ListTagsForResourceCommand,\n } = await import(\"@aws-sdk/client-pinpoint-sms-voice-v2\");\n\n const client = new PinpointSMSVoiceV2Client({ region });\n const protectConfigName = \"wraps-sms-protect\";\n\n // Check if protect configuration already exists by looking up tags\n let existingProtectConfigId: string | undefined;\n try {\n const existing = await client.send(\n new DescribeProtectConfigurationsCommand({})\n );\n\n // Check each protect config's tags to find ours\n for (const pc of existing.ProtectConfigurations || []) {\n if (!(pc.ProtectConfigurationArn && pc.ProtectConfigurationId)) continue;\n\n const tagsResponse = await client.send(\n new ListTagsForResourceCommand({\n ResourceArn: pc.ProtectConfigurationArn,\n })\n );\n\n const nameTag = tagsResponse.Tags?.find((t) => t.Key === \"Name\");\n if (nameTag?.Value === protectConfigName) {\n existingProtectConfigId = pc.ProtectConfigurationId;\n break;\n }\n }\n } catch {\n // May not exist yet\n }\n\n try {\n // Use existing or create new protect configuration\n let protectConfigId = existingProtectConfigId;\n\n if (!protectConfigId) {\n const createResponse = await client.send(\n new CreateProtectConfigurationCommand({\n DeletionProtectionEnabled: false,\n Tags: [\n { Key: \"Name\", Value: protectConfigName },\n { Key: \"ManagedBy\", Value: \"wraps-cli\" },\n { Key: \"Service\", Value: \"sms\" },\n ],\n })\n );\n protectConfigId = createResponse.ProtectConfigurationId;\n }\n\n if (!protectConfigId) {\n throw new Error(\"Failed to create protect configuration\");\n }\n\n // Get all supported countries from the newly created protect config\n // AWS defaults all countries to ALLOW, so we need to get them all and BLOCK them\n const countryRuleSet = await client.send(\n new GetProtectConfigurationCountryRuleSetCommand({\n ProtectConfigurationId: protectConfigId,\n NumberCapability: \"SMS\",\n })\n );\n\n const allowedCountries = options?.allowedCountries || [\"US\"];\n const allowedSet = new Set(allowedCountries);\n\n // Build country rule set - BLOCK all countries except allowed ones\n const countryRuleSetUpdates: Record<\n string,\n { ProtectStatus: \"ALLOW\" | \"BLOCK\" | \"MONITOR\" | \"FILTER\" }\n > = {};\n\n // First, BLOCK all countries that exist in the rule set\n if (countryRuleSet.CountryRuleSet) {\n for (const countryCode of Object.keys(countryRuleSet.CountryRuleSet)) {\n if (allowedSet.has(countryCode)) {\n // Allow this country (with optional AIT filtering)\n countryRuleSetUpdates[countryCode] = {\n ProtectStatus: options?.aitFiltering ? \"FILTER\" : \"ALLOW\",\n };\n } else {\n // Block this country\n countryRuleSetUpdates[countryCode] = {\n ProtectStatus: \"BLOCK\",\n };\n }\n }\n }\n\n // Update country rules for SMS capability\n if (Object.keys(countryRuleSetUpdates).length > 0) {\n // AWS has a limit on batch updates, so we may need to chunk this\n const entries = Object.entries(countryRuleSetUpdates);\n const chunkSize = 100; // AWS limit per request\n\n for (let i = 0; i < entries.length; i += chunkSize) {\n const chunk = entries.slice(i, i + chunkSize);\n const chunkUpdates = Object.fromEntries(chunk);\n\n await client.send(\n new UpdateProtectConfigurationCountryRuleSetCommand({\n ProtectConfigurationId: protectConfigId,\n NumberCapability: \"SMS\",\n CountryRuleSetUpdates: chunkUpdates,\n })\n );\n }\n }\n\n // Associate with configuration set (only if not already associated)\n if (!existingProtectConfigId) {\n await client.send(\n new AssociateProtectConfigurationCommand({\n ProtectConfigurationId: protectConfigId,\n ConfigurationSetName: configurationSetName,\n })\n );\n }\n\n return protectConfigId;\n } catch {\n return;\n }\n}\n\n/**\n * Delete SMS Protect Configuration using AWS SDK\n */\nexport async function deleteSMSProtectConfigurationWithSDK(\n region: string\n): Promise<void> {\n const {\n PinpointSMSVoiceV2Client,\n DeleteProtectConfigurationCommand,\n DescribeProtectConfigurationsCommand,\n ListTagsForResourceCommand,\n } = await import(\"@aws-sdk/client-pinpoint-sms-voice-v2\");\n\n const client = new PinpointSMSVoiceV2Client({ region });\n\n try {\n // Find protect configurations managed by wraps-cli\n const existing = await client.send(\n new DescribeProtectConfigurationsCommand({})\n );\n\n if (existing.ProtectConfigurations) {\n for (const pc of existing.ProtectConfigurations) {\n if (!(pc.ProtectConfigurationArn && pc.ProtectConfigurationId))\n continue;\n\n // Check tags to see if managed by wraps-cli\n const tagsResponse = await client.send(\n new ListTagsForResourceCommand({\n ResourceArn: pc.ProtectConfigurationArn,\n })\n );\n\n const isWrapsManaged = tagsResponse.Tags?.some(\n (t) => t.Key === \"ManagedBy\" && t.Value === \"wraps-cli\"\n );\n\n if (isWrapsManaged) {\n await client.send(\n new DeleteProtectConfigurationCommand({\n ProtectConfigurationId: pc.ProtectConfigurationId,\n })\n );\n }\n }\n }\n } catch {\n // Protect configuration may not exist\n }\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport {\n createSMSEventDestinationWithSDK,\n createSMSPhonePoolWithSDK,\n createSMSProtectConfigurationWithSDK,\n deploySMSStack,\n} from \"../../infrastructure/sms-stack.js\";\nimport {\n trackError,\n trackServiceDeployed,\n trackServiceInit,\n} from \"../../telemetry/events.js\";\nimport type {\n Provider,\n SMSConfigPreset,\n SMSInitOptions,\n SMSStackConfig,\n WrapsSMSConfig,\n} from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { errors } from \"../../utils/shared/errors.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n addServiceToConnection,\n loadConnectionMetadata,\n saveConnectionMetadata,\n} from \"../../utils/shared/metadata.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\nimport {\n confirmDeploy,\n promptProvider,\n promptRegion,\n promptVercelConfig,\n} from \"../../utils/shared/prompts.js\";\nimport { ensurePulumiInstalled } from \"../../utils/shared/pulumi.js\";\nimport { getSMSCostSummary } from \"../../utils/sms/costs.js\";\nimport { getSMSPreset, validateSMSConfig } from \"../../utils/sms/presets.js\";\n\n/**\n * Prompt for phone number type\n */\nasync function promptPhoneNumberType(): Promise<\n \"simulator\" | \"toll-free\" | \"10dlc\"\n> {\n const result = await clack.select({\n message: \"Select phone number type:\",\n options: [\n {\n value: \"simulator\",\n label: \"Simulator ($1/mo)\",\n hint: \"Testing only, 100 msg/day, no registration\",\n },\n {\n value: \"toll-free\",\n label: \"Toll-free ($2/mo)\",\n hint: \"Production, 3 MPS, requires registration (~15 days)\",\n },\n {\n value: \"10dlc\",\n label: \"10DLC ($2/mo + fees)\",\n hint: \"High volume, up to 75 MPS, requires brand + campaign registration\",\n },\n ],\n });\n\n if (clack.isCancel(result)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return result as \"simulator\" | \"toll-free\" | \"10dlc\";\n}\n\n/**\n * Prompt for SMS configuration preset\n */\nasync function promptSMSPreset(): Promise<SMSConfigPreset> {\n const result = await clack.select({\n message: \"Choose configuration preset:\",\n options: [\n {\n value: \"starter\",\n label: \"Starter (~$1/mo)\",\n hint: \"Simulator for testing, basic tracking\",\n },\n {\n value: \"production\",\n label: \"Production (~$2-10/mo)\",\n hint: \"Toll-free, event tracking, message history (RECOMMENDED)\",\n },\n {\n value: \"enterprise\",\n label: \"Enterprise (~$10-50/mo)\",\n hint: \"Full features, link tracking, 1-year history\",\n },\n {\n value: \"custom\",\n label: \"Custom\",\n hint: \"Configure each feature individually\",\n },\n ],\n });\n\n if (clack.isCancel(result)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return result as SMSConfigPreset;\n}\n\n/**\n * Common countries for SMS delivery\n */\nconst COMMON_COUNTRIES = [\n { code: \"US\", name: \"United States\" },\n { code: \"CA\", name: \"Canada\" },\n { code: \"GB\", name: \"United Kingdom\" },\n { code: \"AU\", name: \"Australia\" },\n { code: \"DE\", name: \"Germany\" },\n { code: \"FR\", name: \"France\" },\n { code: \"ES\", name: \"Spain\" },\n { code: \"IT\", name: \"Italy\" },\n { code: \"NL\", name: \"Netherlands\" },\n { code: \"BR\", name: \"Brazil\" },\n { code: \"MX\", name: \"Mexico\" },\n { code: \"IN\", name: \"India\" },\n] as const;\n\n/**\n * Prompt for allowed countries (fraud protection)\n */\nasync function promptAllowedCountries(): Promise<string[]> {\n const result = await clack.multiselect({\n message: \"Select countries to allow SMS delivery (blocks all others):\",\n options: COMMON_COUNTRIES.map((c) => ({\n value: c.code,\n label: `${c.name} (${c.code})`,\n })),\n initialValues: [\"US\"],\n required: true,\n });\n\n if (clack.isCancel(result)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return result as string[];\n}\n\n/**\n * Prompt for estimated message volume\n */\nasync function promptEstimatedSMSVolume(): Promise<number> {\n const result = await clack.select({\n message: \"Estimated messages per month:\",\n options: [\n { value: 100, label: \"< 100 (Testing)\" },\n { value: 1000, label: \"100 - 1,000\" },\n { value: 10_000, label: \"1,000 - 10,000\" },\n { value: 50_000, label: \"10,000 - 50,000\" },\n { value: 100_000, label: \"50,000+\" },\n ],\n });\n\n if (clack.isCancel(result)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n return result as number;\n}\n\n/**\n * Init command - Deploy new SMS infrastructure\n */\nexport async function init(options: SMSInitOptions): Promise<void> {\n const startTime = Date.now();\n\n clack.intro(pc.bold(\"Wraps SMS Infrastructure Setup\"));\n\n const progress = new DeploymentProgress();\n\n // 1. Check Pulumi CLI is installed\n const wasAutoInstalled = await progress.execute(\n \"Checking Pulumi CLI installation\",\n async () => await ensurePulumiInstalled()\n );\n\n if (wasAutoInstalled) {\n progress.info(\"Pulumi CLI was automatically installed\");\n }\n\n // 2. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`Connected to AWS account: ${pc.cyan(identity.accountId)}`);\n\n // 3. Get configuration (from options or prompts)\n const provider: Provider = options.provider || (await promptProvider());\n const region = options.region || (await promptRegion(await getAWSRegion()));\n\n // Get Vercel config if needed\n let vercelConfig;\n if (provider === \"vercel\") {\n vercelConfig = await promptVercelConfig();\n }\n\n // 4. Check if SMS service already exists\n const existingConnection = await loadConnectionMetadata(\n identity.accountId,\n region\n );\n if (existingConnection?.services?.sms) {\n clack.log.warn(\n `SMS already configured for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n clack.log.info(`Use ${pc.cyan(\"wraps sms status\")} to view current setup`);\n process.exit(0);\n }\n\n // 5. Configuration selection\n let preset = options.preset;\n if (!preset) {\n preset = await promptSMSPreset();\n }\n\n let smsConfig: WrapsSMSConfig;\n if (preset === \"custom\") {\n // Custom config - prompt for phone number type\n const phoneNumberType = await promptPhoneNumberType();\n smsConfig = {\n phoneNumberType,\n tracking: { enabled: true, deliveryReports: true },\n eventTracking: { enabled: false },\n optOutManagement: true,\n sendingEnabled: true,\n };\n\n // Ask about event tracking\n const enableEventTracking = await clack.confirm({\n message: \"Enable event tracking (EventBridge + DynamoDB)?\",\n initialValue: false,\n });\n\n if (clack.isCancel(enableEventTracking)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n if (enableEventTracking) {\n smsConfig.eventTracking = {\n enabled: true,\n eventBridge: true,\n events: [\"SENT\", \"DELIVERED\", \"FAILED\", \"OPTED_OUT\"],\n dynamoDBHistory: true,\n archiveRetention: \"90days\",\n };\n }\n } else {\n smsConfig = getSMSPreset(preset)!;\n\n // If starter preset, override to simulator for testing\n if (preset === \"starter\") {\n smsConfig.phoneNumberType = \"simulator\";\n }\n }\n\n // Prompt for allowed countries (fraud protection)\n progress.info(\n `\\n${pc.bold(\"Fraud Protection\")} - Block SMS to countries where you don't do business`\n );\n const allowedCountries = await promptAllowedCountries();\n\n // Ask about AIT filtering for production use (adds per-message cost)\n let aitFiltering = false;\n if (smsConfig.phoneNumberType !== \"simulator\") {\n const enableAIT = await clack.confirm({\n message:\n \"Enable AIT (Artificially Inflated Traffic) filtering? (adds per-message cost)\",\n initialValue: false,\n });\n\n if (clack.isCancel(enableAIT)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n aitFiltering = enableAIT;\n }\n\n // Set protect configuration\n smsConfig.protectConfiguration = {\n enabled: true,\n allowedCountries,\n aitFiltering,\n };\n\n // Get estimated volume for cost calculation\n const estimatedVolume = await promptEstimatedSMSVolume();\n\n // Display cost summary\n progress.info(`\\n${pc.bold(\"Cost Estimate:\")}`);\n const costSummary = getSMSCostSummary(smsConfig, estimatedVolume);\n clack.log.info(costSummary);\n\n // Validate configuration and show warnings\n const warnings = validateSMSConfig(smsConfig);\n if (warnings.length > 0) {\n progress.info(`\\n${pc.yellow(pc.bold(\"Important Notes:\"))}`);\n for (const warning of warnings) {\n clack.log.warn(warning);\n }\n }\n\n // Confirm deployment\n if (!options.yes) {\n const confirmed = await confirmDeploy();\n if (!confirmed) {\n clack.cancel(\"Deployment cancelled.\");\n process.exit(0);\n }\n }\n\n // 6. Build stack configuration\n const stackConfig: SMSStackConfig = {\n provider,\n region,\n vercel: vercelConfig,\n smsConfig,\n };\n\n // 7. Deploy infrastructure using Pulumi\n let outputs: {\n roleArn: string;\n phoneNumber: string | undefined;\n phoneNumberArn: string | undefined;\n configSetName: string | undefined;\n tableName: string | undefined;\n region: string;\n lambdaFunctions: string[] | undefined;\n snsTopicArn: string | undefined;\n queueUrl: string | undefined;\n dlqUrl: string | undefined;\n optOutListArn: string | undefined;\n };\n try {\n outputs = await progress.execute(\n \"Deploying SMS infrastructure (this may take 2-3 minutes)\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName: `wraps-sms-${identity.accountId}-${region}`,\n projectName: \"wraps-sms\",\n program: async () => {\n const result = await deploySMSStack(stackConfig);\n return {\n roleArn: result.roleArn,\n phoneNumber: result.phoneNumber,\n phoneNumberArn: result.phoneNumberArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n snsTopicArn: result.snsTopicArn,\n queueUrl: result.queueUrl,\n dlqUrl: result.dlqUrl,\n optOutListArn: result.optOutListArn,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.setConfig(\"aws:region\", { value: region });\n const upResult = await stack.up({ onOutput: console.log });\n const pulumiOutputs = upResult.outputs;\n\n return {\n roleArn: pulumiOutputs.roleArn?.value as string,\n phoneNumber: pulumiOutputs.phoneNumber?.value as string | undefined,\n phoneNumberArn: pulumiOutputs.phoneNumberArn?.value as\n | string\n | undefined,\n configSetName: pulumiOutputs.configSetName?.value as\n | string\n | undefined,\n tableName: pulumiOutputs.tableName?.value as string | undefined,\n region: pulumiOutputs.region?.value as string,\n lambdaFunctions: pulumiOutputs.lambdaFunctions?.value as\n | string[]\n | undefined,\n snsTopicArn: pulumiOutputs.snsTopicArn?.value as string | undefined,\n queueUrl: pulumiOutputs.queueUrl?.value as string | undefined,\n dlqUrl: pulumiOutputs.dlqUrl?.value as string | undefined,\n optOutListArn: pulumiOutputs.optOutListArn?.value as\n | string\n | undefined,\n };\n }\n );\n\n // 7a. Create phone pool via SDK (after Pulumi deployment)\n if (outputs.phoneNumberArn) {\n await progress.execute(\"Creating phone pool\", async () => {\n await createSMSPhonePoolWithSDK(outputs.phoneNumberArn!, region);\n });\n }\n\n // 7b. Create event destination via SDK (after Pulumi deployment)\n if (\n smsConfig.eventTracking?.enabled &&\n outputs.configSetName &&\n outputs.snsTopicArn\n ) {\n await progress.execute(\"Configuring event destination\", async () => {\n await createSMSEventDestinationWithSDK(\n outputs.configSetName!,\n outputs.snsTopicArn!,\n region\n );\n });\n }\n\n // 7c. Create protect configuration via SDK (fraud protection)\n if (smsConfig.protectConfiguration?.enabled && outputs.configSetName) {\n await progress.execute(\"Configuring fraud protection\", async () => {\n await createSMSProtectConfigurationWithSDK(\n outputs.configSetName!,\n region,\n {\n allowedCountries: smsConfig.protectConfiguration?.allowedCountries,\n aitFiltering: smsConfig.protectConfiguration?.aitFiltering,\n }\n );\n });\n }\n } catch (error: unknown) {\n trackServiceInit(\"sms\", false, {\n preset,\n provider,\n duration_ms: Date.now() - startTime,\n });\n\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (errorMessage.includes(\"stack is currently locked\")) {\n trackError(\"STACK_LOCKED\", \"sms:init\", { step: \"deploy\" });\n throw errors.stackLocked();\n }\n\n trackError(\"DEPLOYMENT_FAILED\", \"sms:init\", { step: \"deploy\" });\n throw new Error(`SMS deployment failed: ${errorMessage}`);\n }\n\n // 8. Save metadata\n const metadata = addServiceToConnection(\n identity.accountId,\n region,\n provider,\n \"sms\",\n smsConfig,\n preset === \"custom\" ? undefined : preset,\n existingConnection || undefined\n );\n if (vercelConfig) {\n metadata.vercel = vercelConfig;\n }\n if (metadata.services.sms) {\n metadata.services.sms.pulumiStackName = `wraps-sms-${identity.accountId}-${region}`;\n }\n await saveConnectionMetadata(metadata);\n\n progress.info(\"Connection metadata saved\");\n\n // 9. Display success message\n console.log(\"\\n\");\n clack.log.success(pc.green(pc.bold(\"SMS infrastructure deployed!\")));\n console.log(\"\\n\");\n\n // Show deployed resources\n clack.note(\n [\n `${pc.bold(\"Phone Number:\")} ${pc.cyan(outputs.phoneNumber || \"Provisioning...\")}`,\n `${pc.bold(\"Phone Type:\")} ${pc.cyan(smsConfig.phoneNumberType || \"simulator\")}`,\n `${pc.bold(\"Config Set:\")} ${pc.cyan(outputs.configSetName || \"wraps-sms-config\")}`,\n `${pc.bold(\"Region:\")} ${pc.cyan(outputs.region)}`,\n outputs.tableName\n ? `${pc.bold(\"History Table:\")} ${pc.cyan(outputs.tableName)}`\n : \"\",\n \"\",\n pc.dim(\"IAM Role:\"),\n pc.dim(` ${outputs.roleArn}`),\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n \"SMS Infrastructure\"\n );\n\n // Show next steps based on phone number type\n const nextSteps = [];\n if (smsConfig.phoneNumberType === \"toll-free\") {\n nextSteps.push(\n `${pc.cyan(\"wraps sms register\")} - Submit toll-free registration (required before sending)`\n );\n }\n nextSteps.push(\n `${pc.cyan(\"wraps sms test --to +1234567890\")} - Send a test message`\n );\n nextSteps.push(`${pc.cyan(\"wraps sms status\")} - View SMS configuration`);\n\n console.log(\"\\n\");\n clack.log.info(pc.bold(\"Next steps:\"));\n for (const step of nextSteps) {\n console.log(` ${step}`);\n }\n\n // Show SDK usage example\n console.log(\"\\n\");\n clack.log.info(pc.bold(\"SDK Usage:\"));\n console.log(pc.dim(\" npm install @wraps.dev/sms\"));\n console.log(\"\");\n console.log(pc.dim(\" import { Wraps } from '@wraps.dev/sms';\"));\n console.log(pc.dim(\" const wraps = new Wraps();\"));\n console.log(pc.dim(\" await wraps.sms.send({\"));\n console.log(pc.dim(\" to: '+14155551234',\"));\n console.log(pc.dim(\" message: 'Your code is 123456',\"));\n console.log(pc.dim(\" });\"));\n\n clack.outro(pc.green(\"Setup complete!\"));\n\n // Track successful deployment\n const duration = Date.now() - startTime;\n const enabledFeatures: string[] = [];\n if (smsConfig.tracking?.enabled) enabledFeatures.push(\"tracking\");\n if (smsConfig.eventTracking?.enabled) enabledFeatures.push(\"event_tracking\");\n if (smsConfig.eventTracking?.dynamoDBHistory)\n enabledFeatures.push(\"dynamodb_history\");\n if (smsConfig.optOutManagement) enabledFeatures.push(\"opt_out_management\");\n\n trackServiceInit(\"sms\", true, {\n preset,\n provider,\n phoneNumberType: smsConfig.phoneNumberType,\n features: enabledFeatures,\n duration_ms: duration,\n });\n\n trackServiceDeployed(\"sms\", {\n duration_ms: duration,\n features: enabledFeatures,\n preset,\n });\n}\n","import type {\n ArchiveRetention,\n FeatureCost,\n SMSFeatureCostBreakdown,\n WrapsSMSConfig,\n} from \"../../types/index.js\";\n\n/**\n * AWS SMS pricing constants (as of 2025)\n * All costs in USD (US region)\n * Source: aws.amazon.com/end-user-messaging/pricing\n */\nconst AWS_SMS_PRICING = {\n // Phone number rental\n SIMULATOR_MONTHLY: 1.0, // $1/month for simulator\n TOLL_FREE_MONTHLY: 2.0, // $2/month for toll-free\n TEN_DLC_MONTHLY: 2.0, // $2/month for 10DLC + campaign fees (~$10/campaign)\n SHORT_CODE_MONTHLY: 995.0, // $995/month for dedicated short code\n\n // Per-message costs (US outbound)\n TOLL_FREE_PER_SMS: 0.0075, // $0.0075 per outbound SMS (toll-free)\n TEN_DLC_PER_SMS: 0.0075, // $0.0075 per outbound SMS (10DLC)\n SHORT_CODE_PER_SMS: 0.0055, // $0.0055 per outbound SMS (short code)\n SIMULATOR_PER_SMS: 0.0, // Free (limited to 100/day)\n\n // Carrier fees (average, varies by carrier)\n CARRIER_FEE_AVERAGE: 0.003, // ~$0.003 per message\n\n // Infrastructure costs (same as email)\n DYNAMODB_WRITE_PER_MILLION: 1.25,\n DYNAMODB_READ_PER_MILLION: 0.25,\n DYNAMODB_STORAGE_PER_GB: 0.25,\n LAMBDA_REQUESTS_PER_MILLION: 0.2,\n LAMBDA_COMPUTE_PER_GB_SECOND: 0.000_016_666_7,\n SQS_REQUESTS_PER_MILLION: 0.5,\n EVENTBRIDGE_EVENTS_PER_MILLION: 1.0,\n} as const;\n\n/**\n * AWS Free tier limits\n */\nconst FREE_TIER = {\n LAMBDA_REQUESTS: 1_000_000,\n LAMBDA_COMPUTE_GB_SECONDS: 400_000,\n DYNAMODB_STORAGE_GB: 25,\n SQS_REQUESTS: 1_000_000,\n} as const;\n\n/**\n * Estimate storage size in GB based on retention period and message volume\n */\nfunction estimateStorageSize(\n messagesPerMonth: number,\n retention: ArchiveRetention,\n numEventTypes = 4\n): number {\n // Average SMS event record size: ~1 KB\n const avgRecordSizeKB = 1;\n\n const retentionMonths = {\n \"7days\": 0.25,\n \"30days\": 1,\n \"90days\": 3,\n \"3months\": 3,\n \"6months\": 6,\n \"9months\": 9,\n \"1year\": 12,\n \"18months\": 18,\n \"2years\": 24,\n \"30months\": 30,\n \"3years\": 36,\n \"4years\": 48,\n \"5years\": 60,\n \"6years\": 72,\n \"7years\": 84,\n \"8years\": 96,\n \"9years\": 108,\n \"10years\": 120,\n indefinite: 120,\n permanent: 120,\n }[retention];\n\n const totalKB =\n messagesPerMonth * numEventTypes * (retentionMonths ?? 3) * avgRecordSizeKB;\n return totalKB / 1024 / 1024; // Convert to GB\n}\n\n/**\n * Calculate phone number cost\n */\nfunction calculatePhoneNumberCost(\n config: WrapsSMSConfig\n): FeatureCost | undefined {\n const phoneType = config.phoneNumberType;\n\n if (!phoneType) {\n return;\n }\n\n const costMap: Record<string, number> = {\n simulator: AWS_SMS_PRICING.SIMULATOR_MONTHLY,\n \"toll-free\": AWS_SMS_PRICING.TOLL_FREE_MONTHLY,\n \"10dlc\": AWS_SMS_PRICING.TEN_DLC_MONTHLY,\n \"short-code\": AWS_SMS_PRICING.SHORT_CODE_MONTHLY,\n };\n\n const descriptions: Record<string, string> = {\n simulator: \"Simulator number (testing only, 100 msg/day limit)\",\n \"toll-free\": \"Toll-free number (3 MPS, requires registration)\",\n \"10dlc\": \"10DLC number (75 MPS, requires brand + campaign registration)\",\n \"short-code\": \"Dedicated short code (100+ MPS, separate application)\",\n };\n\n return {\n monthly: costMap[phoneType] || 0,\n description: descriptions[phoneType] || \"Phone number rental\",\n };\n}\n\n/**\n * Calculate per-message costs\n */\nfunction calculateMessageCost(\n config: WrapsSMSConfig,\n messagesPerMonth: number\n): FeatureCost | undefined {\n const phoneType = config.phoneNumberType;\n\n if (!phoneType || phoneType === \"simulator\") {\n return {\n monthly: 0,\n perMessage: 0,\n description: \"Message sending (simulator - free, limited)\",\n };\n }\n\n const perMessageCost =\n phoneType === \"short-code\"\n ? AWS_SMS_PRICING.SHORT_CODE_PER_SMS\n : AWS_SMS_PRICING.TOLL_FREE_PER_SMS;\n\n const carrierFee = AWS_SMS_PRICING.CARRIER_FEE_AVERAGE;\n const totalPerMessage = perMessageCost + carrierFee;\n const monthlyCost = messagesPerMonth * totalPerMessage;\n\n return {\n monthly: monthlyCost,\n perMessage: totalPerMessage,\n description: `Message sending ($${perMessageCost.toFixed(4)}/msg + ~$${carrierFee.toFixed(3)} carrier fee)`,\n };\n}\n\n/**\n * Calculate event tracking infrastructure cost\n */\nfunction calculateEventTrackingCost(\n config: WrapsSMSConfig,\n messagesPerMonth: number\n): FeatureCost | undefined {\n if (!config.eventTracking?.enabled) {\n return;\n }\n\n let monthlyCost = 0;\n const components: string[] = [];\n\n const numEventTypes = config.eventTracking.events?.length || 4;\n const totalEvents = messagesPerMonth * numEventTypes;\n\n // EventBridge events\n if (config.eventTracking.eventBridge) {\n const eventCost =\n (totalEvents / 1_000_000) *\n AWS_SMS_PRICING.EVENTBRIDGE_EVENTS_PER_MILLION;\n monthlyCost += eventCost;\n components.push(\"EventBridge\");\n }\n\n // SQS queue costs\n const sqsRequests = totalEvents * 3; // send + receive + delete\n const sqsCost =\n (Math.max(0, sqsRequests - FREE_TIER.SQS_REQUESTS) / 1_000_000) *\n AWS_SMS_PRICING.SQS_REQUESTS_PER_MILLION;\n monthlyCost += sqsCost;\n components.push(\"SQS\");\n\n // Lambda processing costs\n const lambdaInvocations = totalEvents;\n const lambdaRequestCost =\n (Math.max(0, lambdaInvocations - FREE_TIER.LAMBDA_REQUESTS) / 1_000_000) *\n AWS_SMS_PRICING.LAMBDA_REQUESTS_PER_MILLION;\n\n const memoryGB = 0.5;\n const avgDurationSeconds = 0.1;\n const computeGBSeconds = lambdaInvocations * memoryGB * avgDurationSeconds;\n const lambdaComputeCost =\n Math.max(0, computeGBSeconds - FREE_TIER.LAMBDA_COMPUTE_GB_SECONDS) *\n AWS_SMS_PRICING.LAMBDA_COMPUTE_PER_GB_SECOND;\n\n monthlyCost += lambdaRequestCost + lambdaComputeCost;\n components.push(\"Lambda\");\n\n return {\n monthly: monthlyCost,\n description: `Event processing (${numEventTypes} event types: ${components.join(\" → \")})`,\n };\n}\n\n/**\n * Calculate DynamoDB history storage cost\n */\nfunction calculateDynamoDBCost(\n config: WrapsSMSConfig,\n messagesPerMonth: number\n): FeatureCost | undefined {\n if (!config.eventTracking?.dynamoDBHistory) {\n return;\n }\n\n const retention = config.eventTracking.archiveRetention || \"90days\";\n const numEventTypes = config.eventTracking.events?.length || 4;\n\n // Write costs\n const totalEvents = messagesPerMonth * numEventTypes;\n const writeCost =\n (totalEvents / 1_000_000) * AWS_SMS_PRICING.DYNAMODB_WRITE_PER_MILLION;\n\n // Storage costs\n const storageGB = estimateStorageSize(\n messagesPerMonth,\n retention,\n numEventTypes\n );\n const storageCost =\n Math.max(0, storageGB - FREE_TIER.DYNAMODB_STORAGE_GB) *\n AWS_SMS_PRICING.DYNAMODB_STORAGE_PER_GB;\n\n return {\n monthly: writeCost + storageCost,\n description: `Message history (${retention}, ~${storageGB.toFixed(3)} GB)`,\n };\n}\n\n/**\n * Calculate tracking cost\n */\nfunction calculateTrackingCost(\n config: WrapsSMSConfig\n): FeatureCost | undefined {\n if (!config.tracking?.enabled) {\n return;\n }\n\n // Basic delivery tracking is included in AWS SMS pricing\n return {\n monthly: 0,\n description: \"Delivery tracking (included)\",\n };\n}\n\n/**\n * Calculate total SMS infrastructure costs\n */\nexport function calculateSMSCosts(\n config: WrapsSMSConfig,\n messagesPerMonth = 1000\n): SMSFeatureCostBreakdown {\n const phoneNumber = calculatePhoneNumberCost(config);\n const tracking = calculateTrackingCost(config);\n const eventTracking = calculateEventTrackingCost(config, messagesPerMonth);\n const dynamoDBHistory = calculateDynamoDBCost(config, messagesPerMonth);\n const messageCost = calculateMessageCost(config, messagesPerMonth);\n\n // Sum all costs\n const totalMonthlyCost =\n (phoneNumber?.monthly || 0) +\n (tracking?.monthly || 0) +\n (eventTracking?.monthly || 0) +\n (dynamoDBHistory?.monthly || 0) +\n (messageCost?.monthly || 0);\n\n return {\n phoneNumber,\n tracking,\n eventTracking,\n dynamoDBHistory,\n total: {\n monthly: totalMonthlyCost,\n perMessage: messageCost?.perMessage || 0,\n description: `Total estimated cost for ${messagesPerMonth.toLocaleString()} messages/month`,\n },\n };\n}\n\n/**\n * Format cost for display\n */\nexport function formatCost(cost: number): string {\n if (cost === 0) {\n return \"Free\";\n }\n if (cost < 0.01) {\n return \"< $0.01\";\n }\n return `~$${cost.toFixed(2)}/mo`;\n}\n\n/**\n * Get cost estimate summary for display\n */\nexport function getSMSCostSummary(\n config: WrapsSMSConfig,\n messagesPerMonth = 1000\n): string {\n const costs = calculateSMSCosts(config, messagesPerMonth);\n const lines: string[] = [];\n\n lines.push(\n `Estimated cost for ${messagesPerMonth.toLocaleString()} messages/month: ${formatCost(costs.total.monthly)}`\n );\n\n if (costs.phoneNumber) {\n lines.push(\n ` - ${costs.phoneNumber.description}: $${costs.phoneNumber.monthly.toFixed(2)}/mo`\n );\n }\n\n if (costs.total.perMessage && costs.total.perMessage > 0) {\n lines.push(\n ` - Message costs: $${((costs.total.perMessage || 0) * 1000).toFixed(2)}/1k messages`\n );\n }\n\n if (costs.tracking) {\n lines.push(` - ${costs.tracking.description}`);\n }\n\n if (costs.eventTracking) {\n lines.push(\n ` - ${costs.eventTracking.description}: $${costs.eventTracking.monthly.toFixed(2)}/mo`\n );\n }\n\n if (costs.dynamoDBHistory) {\n lines.push(\n ` - ${costs.dynamoDBHistory.description}: $${costs.dynamoDBHistory.monthly.toFixed(2)}/mo`\n );\n }\n\n return lines.join(\"\\n\");\n}\n","import type { SMSConfigPreset, WrapsSMSConfig } from \"../../types/index.js\";\nimport { calculateSMSCosts, formatCost } from \"./costs.js\";\n\n/**\n * Preset configurations with recommended settings for different use cases\n */\n\n/**\n * Starter preset - minimal features for testing and low-volume\n * Perfect for: Development, testing, MVPs\n * Volume: Up to 100 messages/day (simulator limit)\n * Cost: ~$1/month (simulator number only)\n */\nexport const SMS_STARTER_PRESET: WrapsSMSConfig = {\n phoneNumberType: \"simulator\",\n tracking: {\n enabled: true,\n deliveryReports: true,\n },\n eventTracking: {\n enabled: false,\n },\n optOutManagement: true,\n sendingEnabled: true,\n protectConfiguration: {\n enabled: true,\n allowedCountries: [\"US\"],\n aitFiltering: false,\n },\n};\n\n/**\n * Production preset - recommended for most production applications\n * Perfect for: SaaS apps, OTP/verification, transactional SMS\n * Volume: Unlimited (3 MPS with toll-free)\n * Cost: ~$2-10/month (includes toll-free number + event tracking)\n */\nexport const SMS_PRODUCTION_PRESET: WrapsSMSConfig = {\n phoneNumberType: \"toll-free\",\n tracking: {\n enabled: true,\n deliveryReports: true,\n },\n eventTracking: {\n enabled: true,\n eventBridge: true,\n events: [\"SENT\", \"DELIVERED\", \"FAILED\", \"OPTED_OUT\"],\n dynamoDBHistory: true,\n archiveRetention: \"90days\",\n },\n optOutManagement: true,\n sendingEnabled: true,\n protectConfiguration: {\n enabled: true,\n allowedCountries: [\"US\"],\n aitFiltering: false, // No extra cost by default\n },\n};\n\n/**\n * Enterprise preset - full features for high-volume senders\n * Perfect for: Large platforms, high-volume transactional SMS\n * Volume: High (10DLC recommended for 75+ MPS)\n * Cost: ~$10-50/month (toll-free + full tracking + 1-year history)\n */\nexport const SMS_ENTERPRISE_PRESET: WrapsSMSConfig = {\n phoneNumberType: \"toll-free\",\n tracking: {\n enabled: true,\n deliveryReports: true,\n linkTracking: true,\n },\n eventTracking: {\n enabled: true,\n eventBridge: true,\n events: [\n \"SENT\",\n \"DELIVERED\",\n \"FAILED\",\n \"QUEUED\",\n \"CARRIER_UNREACHABLE\",\n \"BLOCKED\",\n \"INVALID\",\n \"OPTED_OUT\",\n \"TTL_EXPIRED\",\n ],\n dynamoDBHistory: true,\n archiveRetention: \"1year\",\n },\n messageArchiving: {\n enabled: true,\n retention: \"1year\",\n },\n optOutManagement: true,\n sendingEnabled: true,\n protectConfiguration: {\n enabled: true,\n allowedCountries: [\"US\"],\n aitFiltering: false, // No extra cost by default\n },\n};\n\n/**\n * Get preset configuration by name\n */\nexport function getSMSPreset(preset: SMSConfigPreset): WrapsSMSConfig | null {\n switch (preset) {\n case \"starter\":\n return SMS_STARTER_PRESET;\n case \"production\":\n return SMS_PRODUCTION_PRESET;\n case \"enterprise\":\n return SMS_ENTERPRISE_PRESET;\n case \"custom\":\n return null; // User will configure manually\n }\n}\n\n/**\n * Preset metadata for display\n */\nexport type SMSPresetInfo = {\n name: string;\n description: string;\n recommended: string;\n throughput: string;\n estimatedCost: string;\n features: string[];\n};\n\n/**\n * Get preset information for display\n */\nexport function getSMSPresetInfo(preset: SMSConfigPreset): SMSPresetInfo {\n const config = getSMSPreset(preset);\n\n if (preset === \"custom\" || !config) {\n return {\n name: \"Custom\",\n description: \"Configure each feature individually\",\n recommended: \"Advanced users who need specific configuration\",\n throughput: \"Varies by number type\",\n estimatedCost: \"Varies\",\n features: [\"Full control over all features\"],\n };\n }\n\n const messagesPerMonth =\n preset === \"starter\" ? 1000 : preset === \"production\" ? 10_000 : 100_000;\n\n const costs = calculateSMSCosts(config, messagesPerMonth);\n\n const baseInfo = {\n starter: {\n name: \"Starter\",\n description: \"Simulator for testing (no real messages)\",\n recommended: \"Development, testing, MVPs\",\n throughput: \"100 messages/day (simulator limit)\",\n features: [\n \"Simulator phone number ($1/mo)\",\n \"Delivery status tracking\",\n \"Automatic opt-out management\",\n \"No registration required\",\n ],\n },\n production: {\n name: \"Production\",\n description: \"Toll-free number for production use\",\n recommended: \"SaaS apps, OTP, transactional SMS (RECOMMENDED)\",\n throughput: \"3 messages/second\",\n features: [\n \"Toll-free number ($2/mo)\",\n \"Real-time event tracking (EventBridge)\",\n \"90-day message history storage\",\n \"Automatic opt-out management\",\n \"Requires registration (~15 business days)\",\n ],\n },\n enterprise: {\n name: \"Enterprise\",\n description: \"Full features for high-volume senders\",\n recommended: \"Large platforms, high-volume transactional SMS\",\n throughput: \"3 MPS (toll-free) or 75+ MPS (10DLC)\",\n features: [\n \"Everything in Production\",\n \"Link click tracking\",\n \"Message content archiving\",\n \"1-year message history\",\n \"All event types tracked\",\n ],\n },\n }[preset];\n\n return {\n ...baseInfo,\n estimatedCost: formatCost(costs.total.monthly),\n } as SMSPresetInfo;\n}\n\n/**\n * Get all preset options for CLI prompts\n */\nexport function getAllSMSPresetInfo(): SMSPresetInfo[] {\n return [\n getSMSPresetInfo(\"starter\"),\n getSMSPresetInfo(\"production\"),\n getSMSPresetInfo(\"enterprise\"),\n getSMSPresetInfo(\"custom\"),\n ];\n}\n\n/**\n * Compare two configurations to determine upgrade path\n */\nexport function getSMSUpgradePath(\n current: WrapsSMSConfig,\n target: WrapsSMSConfig\n): string[] {\n const changes: string[] = [];\n\n // Check phone number type upgrade\n if (current.phoneNumberType !== target.phoneNumberType) {\n changes.push(\n `Upgrade phone number: ${current.phoneNumberType || \"none\"} → ${target.phoneNumberType}`\n );\n }\n\n // Check event tracking\n if (!current.eventTracking?.enabled && target.eventTracking?.enabled) {\n changes.push(\"Enable real-time event tracking\");\n }\n\n // Check DynamoDB history\n if (\n !current.eventTracking?.dynamoDBHistory &&\n target.eventTracking?.dynamoDBHistory\n ) {\n changes.push(\"Enable message history storage\");\n }\n\n // Check retention upgrade\n if (\n current.eventTracking?.archiveRetention !==\n target.eventTracking?.archiveRetention &&\n target.eventTracking?.archiveRetention\n ) {\n changes.push(\n `Upgrade retention: ${current.eventTracking?.archiveRetention || \"none\"} → ${target.eventTracking.archiveRetention}`\n );\n }\n\n // Check message archiving\n if (!current.messageArchiving?.enabled && target.messageArchiving?.enabled) {\n changes.push(\"Enable message content archiving\");\n }\n\n // Check link tracking\n if (!current.tracking?.linkTracking && target.tracking?.linkTracking) {\n changes.push(\"Enable link click tracking\");\n }\n\n return changes;\n}\n\n/**\n * Validate configuration for common issues\n */\nexport function validateSMSConfig(config: WrapsSMSConfig): string[] {\n const warnings: string[] = [];\n\n // Warn about simulator in production\n if (config.phoneNumberType === \"simulator\") {\n warnings.push(\n \"Simulator numbers cannot send real SMS. Use toll-free for production.\"\n );\n }\n\n // Warn about toll-free registration\n if (config.phoneNumberType === \"toll-free\") {\n warnings.push(\n \"Toll-free numbers require registration (~15 business days). Run 'wraps sms register' after setup.\"\n );\n }\n\n // Warn about event tracking without storage\n if (config.eventTracking?.enabled && !config.eventTracking?.dynamoDBHistory) {\n warnings.push(\n \"Event tracking is enabled but history storage is disabled. Events will only be available in real-time.\"\n );\n }\n\n // Warn about long retention\n if (config.eventTracking?.archiveRetention === \"indefinite\") {\n warnings.push(\n \"Indefinite retention can become expensive. Consider 90-day or 1-year retention.\"\n );\n }\n\n return warnings;\n}\n","import * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { loadConnectionMetadata } from \"../../utils/shared/metadata.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\n\ntype SMSRegisterOptions = {\n region?: string;\n};\n\n/**\n * Get phone number details from AWS\n */\nasync function getPhoneNumberDetails(region: string): Promise<{\n phoneNumber: string;\n phoneNumberArn: string;\n status: string;\n type: string;\n registrationId?: string;\n} | null> {\n const { PinpointSMSVoiceV2Client, DescribePhoneNumbersCommand } =\n await import(\"@aws-sdk/client-pinpoint-sms-voice-v2\");\n\n const client = new PinpointSMSVoiceV2Client({ region });\n\n try {\n const response = await client.send(new DescribePhoneNumbersCommand({}));\n\n // Find wraps-managed phone number\n for (const phone of response.PhoneNumbers || []) {\n if (phone.OptOutListName === \"wraps-sms-optouts\") {\n return {\n phoneNumber: phone.PhoneNumber || \"\",\n phoneNumberArn: phone.PhoneNumberArn || \"\",\n status: phone.Status || \"UNKNOWN\",\n type: phone.NumberType || \"UNKNOWN\",\n registrationId: phone.RegistrationId,\n };\n }\n }\n return null;\n } catch (error) {\n console.error(\"Error fetching phone number:\", error);\n return null;\n }\n}\n\n/**\n * Get registration status if available\n */\nasync function getRegistrationStatus(\n region: string,\n registrationId: string\n): Promise<string | null> {\n const { PinpointSMSVoiceV2Client, DescribeRegistrationsCommand } =\n await import(\"@aws-sdk/client-pinpoint-sms-voice-v2\");\n\n const client = new PinpointSMSVoiceV2Client({ region });\n\n try {\n const response = await client.send(\n new DescribeRegistrationsCommand({\n RegistrationIds: [registrationId],\n })\n );\n\n return response.Registrations?.[0]?.RegistrationStatus || null;\n } catch {\n return null;\n }\n}\n\n/**\n * SMS Register command - Help register toll-free numbers\n */\nexport async function smsRegister(options: SMSRegisterOptions): Promise<void> {\n clack.intro(pc.bold(\"Wraps SMS - Toll-Free Registration\"));\n\n const progress = new DeploymentProgress();\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region\n let region = options.region;\n if (!region) {\n region = await getAWSRegion();\n }\n\n // 3. Load metadata\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n\n if (!metadata?.services?.sms) {\n clack.log.error(\"No SMS infrastructure found.\");\n clack.log.info(`Run ${pc.cyan(\"wraps sms init\")} first.`);\n process.exit(1);\n }\n\n // 4. Get phone number details\n const phoneDetails = await progress.execute(\n \"Checking phone number status\",\n async () => getPhoneNumberDetails(region!)\n );\n\n if (!phoneDetails) {\n clack.log.error(\"No phone number found.\");\n process.exit(1);\n }\n\n console.log(\"\");\n console.log(\n `${pc.bold(\"Phone Number:\")} ${pc.cyan(phoneDetails.phoneNumber)}`\n );\n console.log(`${pc.bold(\"Type:\")} ${pc.cyan(phoneDetails.type)}`);\n console.log(\n `${pc.bold(\"Status:\")} ${phoneDetails.status === \"ACTIVE\" ? pc.green(phoneDetails.status) : pc.yellow(phoneDetails.status)}`\n );\n\n // 5. Check registration status if available\n if (phoneDetails.registrationId) {\n const regStatus = await getRegistrationStatus(\n region,\n phoneDetails.registrationId\n );\n if (regStatus) {\n console.log(`${pc.bold(\"Registration:\")} ${pc.cyan(regStatus)}`);\n }\n }\n\n console.log(\"\");\n\n // 6. Handle based on status\n if (phoneDetails.status === \"ACTIVE\") {\n clack.log.success(\"Your phone number is already ACTIVE and ready to use!\");\n\n // Check if pool exists\n const { PinpointSMSVoiceV2Client, DescribePoolsCommand } = await import(\n \"@aws-sdk/client-pinpoint-sms-voice-v2\"\n );\n const client = new PinpointSMSVoiceV2Client({ region });\n const pools = await client.send(new DescribePoolsCommand({}));\n\n if (!pools.Pools?.length) {\n clack.log.info(\"Run `wraps sms sync` to create the phone pool.\");\n }\n\n process.exit(0);\n }\n\n if (phoneDetails.type !== \"TOLL_FREE\") {\n clack.log.info(\"Only toll-free numbers require registration.\");\n clack.log.info(`Your ${phoneDetails.type} number should be ready to use.`);\n process.exit(0);\n }\n\n // 7. Show registration instructions\n console.log(pc.bold(\"Toll-Free Registration Required\"));\n console.log(\"\");\n console.log(\n pc.dim(\"To send SMS at scale, you must register your toll-free number.\")\n );\n console.log(pc.dim(\"This process typically takes 1-15 business days.\"));\n console.log(\"\");\n\n console.log(pc.bold(\"You'll need to provide:\"));\n console.log(` ${pc.dim(\"•\")} Business name and address`);\n console.log(\n ` ${pc.dim(\"•\")} Use case description (what messages you're sending)`\n );\n console.log(` ${pc.dim(\"•\")} Sample messages (2-3 examples)`);\n console.log(` ${pc.dim(\"•\")} How users opt-in to receive messages`);\n console.log(` ${pc.dim(\"•\")} Expected monthly message volume`);\n console.log(\"\");\n\n // 8. Offer to open AWS console\n const openConsole = await clack.confirm({\n message: \"Open AWS Console to start registration?\",\n initialValue: true,\n });\n\n if (clack.isCancel(openConsole)) {\n clack.cancel(\"Registration cancelled.\");\n process.exit(0);\n }\n\n if (openConsole) {\n const consoleUrl = `https://${region}.console.aws.amazon.com/sms-voice/home?region=${region}#/registrations`;\n\n // Open browser\n const { exec } = await import(\"node:child_process\");\n const { promisify } = await import(\"node:util\");\n const execAsync = promisify(exec);\n\n try {\n // macOS\n await execAsync(`open \"${consoleUrl}\"`);\n clack.log.success(\"Opened AWS Console in your browser.\");\n } catch {\n try {\n // Linux\n await execAsync(`xdg-open \"${consoleUrl}\"`);\n clack.log.success(\"Opened AWS Console in your browser.\");\n } catch {\n // Fallback - just show the URL\n clack.log.info(\"Open this URL in your browser:\");\n console.log(`\\n ${pc.cyan(consoleUrl)}\\n`);\n }\n }\n\n console.log(\"\");\n console.log(pc.bold(\"Next Steps:\"));\n console.log(\n ` 1. Click ${pc.cyan(\"Create registration\")} in the AWS Console`\n );\n console.log(` 2. Select ${pc.cyan(\"Toll-free number registration\")}`);\n console.log(\" 3. Fill out the business information form\");\n console.log(\" 4. Submit and wait for approval (1-15 business days)\");\n console.log(\"\");\n console.log(\n pc.dim(\"Once approved, run `wraps sms sync` to complete setup.\")\n );\n } else {\n const consoleUrl = `https://${region}.console.aws.amazon.com/sms-voice/home?region=${region}#/registrations`;\n console.log(\"\");\n console.log(\"When you're ready, go to:\");\n console.log(` ${pc.cyan(consoleUrl)}`);\n }\n\n clack.outro(pc.dim(\"Good luck with your registration!\"));\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport { trackCommand } from \"../../telemetry/events.js\";\nimport type { SMSStatusOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport { loadConnectionMetadata } from \"../../utils/shared/metadata.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\n\n/**\n * Display SMS status in a formatted box\n */\nfunction displaySMSStatus(options: {\n region: string;\n phoneNumber?: string;\n phoneNumberType?: string;\n configSetName?: string;\n tableName?: string;\n queueUrl?: string;\n eventTracking: boolean;\n roleArn?: string;\n preset?: string;\n}) {\n const lines: string[] = [];\n\n // Header\n lines.push(pc.bold(pc.green(\"SMS Infrastructure Active\")));\n lines.push(\"\");\n\n // Phone number section\n lines.push(pc.bold(\"Phone Number\"));\n if (options.phoneNumber) {\n lines.push(` Number: ${pc.cyan(options.phoneNumber)}`);\n } else {\n lines.push(` Number: ${pc.yellow(\"Provisioning...\")}`);\n }\n lines.push(` Type: ${pc.cyan(options.phoneNumberType || \"simulator\")}`);\n lines.push(\"\");\n\n // Configuration\n lines.push(pc.bold(\"Configuration\"));\n lines.push(` Region: ${pc.cyan(options.region)}`);\n if (options.preset) {\n lines.push(` Preset: ${pc.cyan(options.preset)}`);\n }\n if (options.configSetName) {\n lines.push(` Config Set: ${pc.cyan(options.configSetName)}`);\n }\n lines.push(\"\");\n\n // Features\n lines.push(pc.bold(\"Features\"));\n lines.push(\n ` Event Tracking: ${options.eventTracking ? pc.green(\"Enabled\") : pc.dim(\"Disabled\")}`\n );\n if (options.tableName) {\n lines.push(` Message History: ${pc.green(\"Enabled\")}`);\n lines.push(` Table: ${pc.dim(options.tableName)}`);\n }\n if (options.queueUrl) {\n lines.push(` Event Queue: ${pc.green(\"Enabled\")}`);\n }\n lines.push(\"\");\n\n // IAM Role\n if (options.roleArn) {\n lines.push(pc.bold(\"IAM Role\"));\n lines.push(` ${pc.dim(options.roleArn)}`);\n }\n\n clack.note(lines.join(\"\\n\"), \"SMS Status\");\n}\n\n/**\n * SMS Status command - Show current SMS infrastructure setup\n */\nexport async function smsStatus(_options: SMSStatusOptions): Promise<void> {\n const startTime = Date.now();\n const progress = new DeploymentProgress();\n\n clack.intro(pc.bold(\"Wraps SMS Status\"));\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Loading SMS infrastructure status\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region\n const region = await getAWSRegion();\n\n // 3. Check for existing metadata\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n\n if (!metadata?.services?.sms) {\n progress.stop();\n clack.log.error(\"No SMS infrastructure found\");\n console.log(\n `\\nRun ${pc.cyan(\"wraps sms init\")} to deploy SMS infrastructure.\\n`\n );\n process.exit(1);\n }\n\n // 4. Try to load Pulumi stack\n let stackOutputs: Record<string, pulumi.automation.OutputValue> = {};\n try {\n await ensurePulumiWorkDir();\n\n const stackName =\n metadata.services.sms.pulumiStackName ||\n `wraps-sms-${identity.accountId}-${region}`;\n\n const stack = await pulumi.automation.LocalWorkspace.selectStack({\n stackName,\n workDir: getPulumiWorkDir(),\n });\n\n stackOutputs = await stack.outputs();\n } catch (_error: unknown) {\n // Stack might not exist, continue with metadata only\n progress.info(\"Unable to load Pulumi stack, showing metadata only\");\n }\n\n // 5. Display status\n progress.stop();\n\n const smsConfig = metadata.services.sms.config;\n displaySMSStatus({\n region,\n phoneNumber: stackOutputs.phoneNumber?.value as string | undefined,\n phoneNumberType: smsConfig?.phoneNumberType,\n configSetName: stackOutputs.configSetName?.value as string | undefined,\n tableName: stackOutputs.tableName?.value as string | undefined,\n queueUrl: stackOutputs.queueUrl?.value as string | undefined,\n eventTracking: smsConfig?.eventTracking?.enabled ?? false,\n roleArn: stackOutputs.roleArn?.value as string | undefined,\n preset: metadata.services.sms.preset,\n });\n\n // 6. Show next steps\n console.log(\"\");\n clack.log.info(pc.bold(\"Commands:\"));\n console.log(\n ` ${pc.cyan(\"wraps sms test --to +1234567890\")} - Send a test message`\n );\n console.log(` ${pc.cyan(\"wraps sms destroy\")} - Remove SMS infrastructure`);\n\n // 7. Track status command\n trackCommand(\"sms:status\", {\n success: true,\n phone_type: smsConfig?.phoneNumberType,\n event_tracking: smsConfig?.eventTracking?.enabled,\n duration_ms: Date.now() - startTime,\n });\n\n clack.outro(pc.dim(\"SMS infrastructure is ready\"));\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport {\n createSMSEventDestinationWithSDK,\n createSMSPhonePoolWithSDK,\n createSMSProtectConfigurationWithSDK,\n deploySMSStack,\n} from \"../../infrastructure/sms-stack.js\";\nimport { trackCommand, trackError } from \"../../telemetry/events.js\";\nimport type { SMSStackConfig } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { errors } from \"../../utils/shared/errors.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n loadConnectionMetadata,\n saveConnectionMetadata,\n} from \"../../utils/shared/metadata.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\n\nexport type SMSSyncOptions = {\n region?: string;\n yes?: boolean;\n};\n\n/**\n * SMS Sync command - Update infrastructure without changing config\n * This is useful for:\n * - Updating Lambda code when CLI is upgraded\n * - Applying new features added in CLI updates\n * - Recreating SDK resources if they were accidentally deleted\n */\nexport async function smsSync(options: SMSSyncOptions): Promise<void> {\n const startTime = Date.now();\n\n clack.intro(pc.bold(\"Wraps SMS Infrastructure Sync\"));\n\n const progress = new DeploymentProgress();\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region\n const region = options.region || (await getAWSRegion());\n\n // 3. Load existing metadata\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n const smsService = metadata?.services?.sms;\n\n if (!smsService?.config) {\n progress.stop();\n clack.log.error(\"No SMS infrastructure found to sync\");\n console.log(\n `\\nRun ${pc.cyan(\"wraps sms init\")} to deploy SMS infrastructure first.\\n`\n );\n process.exit(1);\n }\n\n const smsConfig = smsService.config;\n const storedStackName = smsService.pulumiStackName;\n\n progress.info(\"Found existing SMS configuration\");\n progress.info(\n `Phone type: ${pc.cyan(smsConfig.phoneNumberType || \"simulator\")}`\n );\n progress.info(\n `Event tracking: ${pc.cyan(smsConfig.eventTracking?.enabled ? \"enabled\" : \"disabled\")}`\n );\n\n // 4. Confirm sync\n if (!options.yes) {\n const confirmed = await clack.confirm({\n message:\n \"Sync SMS infrastructure? This will update Lambda code and recreate any missing resources.\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel(\"Sync cancelled.\");\n process.exit(0);\n }\n }\n\n // 5. Build stack configuration from saved metadata\n const stackConfig: SMSStackConfig = {\n provider: metadata?.provider || \"aws\",\n region,\n vercel: metadata?.vercel,\n smsConfig,\n };\n\n // 6. Run Pulumi up to sync infrastructure\n let outputs: {\n roleArn: string;\n phoneNumber: string | undefined;\n phoneNumberArn: string | undefined;\n configSetName: string | undefined;\n tableName: string | undefined;\n region: string;\n lambdaFunctions: string[] | undefined;\n snsTopicArn: string | undefined;\n queueUrl: string | undefined;\n dlqUrl: string | undefined;\n optOutListArn: string | undefined;\n };\n\n try {\n outputs = await progress.execute(\"Syncing SMS infrastructure\", async () => {\n await ensurePulumiWorkDir();\n\n const stackName =\n storedStackName || `wraps-sms-${identity.accountId}-${region}`;\n\n const stack = await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName,\n projectName: \"wraps-sms\",\n program: async () => {\n const result = await deploySMSStack(stackConfig);\n return {\n roleArn: result.roleArn,\n phoneNumber: result.phoneNumber,\n phoneNumberArn: result.phoneNumberArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n snsTopicArn: result.snsTopicArn,\n queueUrl: result.queueUrl,\n dlqUrl: result.dlqUrl,\n optOutListArn: result.optOutListArn,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.setConfig(\"aws:region\", { value: region });\n const upResult = await stack.up({ onOutput: () => {} });\n const pulumiOutputs = upResult.outputs;\n\n return {\n roleArn: pulumiOutputs.roleArn?.value as string,\n phoneNumber: pulumiOutputs.phoneNumber?.value as string | undefined,\n phoneNumberArn: pulumiOutputs.phoneNumberArn?.value as\n | string\n | undefined,\n configSetName: pulumiOutputs.configSetName?.value as string | undefined,\n tableName: pulumiOutputs.tableName?.value as string | undefined,\n region: pulumiOutputs.region?.value as string,\n lambdaFunctions: pulumiOutputs.lambdaFunctions?.value as\n | string[]\n | undefined,\n snsTopicArn: pulumiOutputs.snsTopicArn?.value as string | undefined,\n queueUrl: pulumiOutputs.queueUrl?.value as string | undefined,\n dlqUrl: pulumiOutputs.dlqUrl?.value as string | undefined,\n optOutListArn: pulumiOutputs.optOutListArn?.value as string | undefined,\n };\n });\n\n // 7a. Ensure phone pool exists\n if (outputs.phoneNumberArn) {\n await progress.execute(\"Ensuring phone pool exists\", async () => {\n await createSMSPhonePoolWithSDK(outputs.phoneNumberArn!, region);\n });\n }\n\n // 7b. Ensure event destination exists (if event tracking enabled)\n if (\n smsConfig.eventTracking?.enabled &&\n outputs.configSetName &&\n outputs.snsTopicArn\n ) {\n await progress.execute(\"Ensuring event destination exists\", async () => {\n await createSMSEventDestinationWithSDK(\n outputs.configSetName!,\n outputs.snsTopicArn!,\n region\n );\n });\n }\n\n // 7c. Ensure protect configuration exists (always create for fraud protection)\n // This ensures older deployments get protect config when syncing with newer CLI\n if (outputs.configSetName) {\n await progress.execute(\"Ensuring fraud protection exists\", async () => {\n await createSMSProtectConfigurationWithSDK(\n outputs.configSetName!,\n region,\n {\n // Use saved config if available, otherwise default to US only without AIT filtering (no extra cost)\n allowedCountries: smsConfig.protectConfiguration\n ?.allowedCountries || [\"US\"],\n aitFiltering: smsConfig.protectConfiguration?.aitFiltering ?? false,\n }\n );\n });\n\n // Update metadata to include protect configuration if not present\n if (!smsConfig.protectConfiguration) {\n smsConfig.protectConfiguration = {\n enabled: true,\n allowedCountries: [\"US\"],\n aitFiltering: true,\n };\n }\n }\n } catch (error: unknown) {\n progress.stop();\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (errorMessage.includes(\"stack is currently locked\")) {\n trackError(\"STACK_LOCKED\", \"sms:sync\", { step: \"sync\" });\n throw errors.stackLocked();\n }\n\n trackError(\"SYNC_FAILED\", \"sms:sync\", { step: \"sync\" });\n clack.log.error(`SMS sync failed: ${errorMessage}`);\n process.exit(1);\n }\n\n // 8. Update metadata timestamp\n if (metadata && smsService) {\n smsService.deployedAt = new Date().toISOString();\n await saveConnectionMetadata(metadata);\n }\n\n progress.stop();\n\n // 9. Display success\n console.log(\"\\n\");\n clack.log.success(pc.green(\"SMS infrastructure synced successfully!\"));\n\n const changes: string[] = [];\n if (outputs.lambdaFunctions?.length) {\n changes.push(\"Lambda functions updated\");\n }\n changes.push(\"SDK resources verified\");\n\n console.log(\"\");\n for (const change of changes) {\n console.log(` ${pc.green(\"✓\")} ${change}`);\n }\n\n trackCommand(\"sms:sync\", {\n success: true,\n duration_ms: Date.now() - startTime,\n });\n\n clack.outro(pc.green(\"Sync complete!\"));\n}\n","import {\n PinpointSMSVoiceV2Client,\n SendTextMessageCommand,\n} from \"@aws-sdk/client-pinpoint-sms-voice-v2\";\nimport * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { trackCommand, trackError } from \"../../telemetry/events.js\";\nimport type { SMSTestOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { loadConnectionMetadata } from \"../../utils/shared/metadata.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\n\n/**\n * Validate phone number format (E.164)\n */\nfunction isValidPhoneNumber(phone: string): boolean {\n // E.164 format: +[country code][number]\n return /^\\+[1-9]\\d{1,14}$/.test(phone);\n}\n\n/**\n * AWS SMS Simulator destination numbers for testing\n * These work in sandbox mode without needing to verify a real number\n */\nconst SIMULATOR_DESTINATIONS = [\n { number: \"+14254147755\", country: \"United States (US)\" },\n { number: \"+447860019066\", country: \"United Kingdom (GB)\" },\n { number: \"+61455944038\", country: \"Australia (AU)\" },\n { number: \"+33755512501\", country: \"France (FR)\" },\n { number: \"+4525919410\", country: \"Denmark (DK)\" },\n { number: \"+34683783440\", country: \"Spain (ES)\" },\n { number: \"+46790645100\", country: \"Sweden (SE)\" },\n { number: \"+31970008100148\", country: \"Netherlands (NL)\" },\n] as const;\n\n/**\n * SMS Test command - Send a test SMS message\n */\nexport async function smsTest(options: SMSTestOptions): Promise<void> {\n const startTime = Date.now();\n const progress = new DeploymentProgress();\n\n clack.intro(pc.bold(\"Wraps SMS Test\"));\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region\n const region = await getAWSRegion();\n\n // 3. Check for existing metadata\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n\n if (!metadata?.services?.sms) {\n progress.stop();\n clack.log.error(\"No SMS infrastructure found\");\n console.log(\n `\\nRun ${pc.cyan(\"wraps sms init\")} to deploy SMS infrastructure.\\n`\n );\n process.exit(1);\n }\n\n // 4. Get phone number to send to\n let toNumber = options.to;\n if (!toNumber) {\n // First ask if they want to use a simulator number or enter their own\n const destinationType = await clack.select({\n message: \"Choose destination number:\",\n options: [\n {\n value: \"simulator\",\n label: \"Use simulator number\",\n hint: \"Pre-verified AWS numbers for testing (sandbox mode)\",\n },\n {\n value: \"custom\",\n label: \"Enter custom number\",\n hint: \"Must be verified in sandbox mode\",\n },\n ],\n });\n\n if (clack.isCancel(destinationType)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n if (destinationType === \"simulator\") {\n // Show simulator number options\n const simResult = await clack.select({\n message: \"Select simulator destination:\",\n options: SIMULATOR_DESTINATIONS.map((sim) => ({\n value: sim.number,\n label: `${sim.number} | ${sim.country}`,\n })),\n });\n\n if (clack.isCancel(simResult)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n toNumber = simResult as string;\n } else {\n // Custom number entry\n const result = await clack.text({\n message: \"Enter destination phone number (E.164 format):\",\n placeholder: \"+14155551234\",\n validate: (value) => {\n if (!value) return \"Phone number is required\";\n if (!isValidPhoneNumber(value)) {\n return \"Please enter a valid phone number in E.164 format (e.g., +14155551234)\";\n }\n return;\n },\n });\n\n if (clack.isCancel(result)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n toNumber = result;\n }\n } else if (!isValidPhoneNumber(toNumber)) {\n progress.stop();\n clack.log.error(\n `Invalid phone number format: ${toNumber}. Use E.164 format (e.g., +14155551234)`\n );\n process.exit(1);\n }\n\n // 5. Get message\n let message = options.message;\n if (!message) {\n const result = await clack.text({\n message: \"Enter test message:\",\n placeholder: \"Hello from Wraps SMS!\",\n defaultValue: \"Hello from Wraps SMS! This is a test message.\",\n validate: (value) => {\n if (!value) return \"Message is required\";\n if (value.length > 160) {\n return `Message is ${value.length} characters. SMS messages over 160 characters will be split.`;\n }\n return;\n },\n });\n\n if (clack.isCancel(result)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n message = result;\n }\n\n // 6. Send test message\n const smsConfig = metadata.services.sms.config;\n const configSetName = \"wraps-sms-config\";\n\n try {\n const messageId = await progress.execute(\n `Sending test SMS to ${toNumber}`,\n async () => {\n const client = new PinpointSMSVoiceV2Client({ region });\n\n const command = new SendTextMessageCommand({\n DestinationPhoneNumber: toNumber,\n MessageBody: message,\n ConfigurationSetName: configSetName,\n MessageType: \"TRANSACTIONAL\",\n });\n\n const response = await client.send(command);\n return response.MessageId;\n }\n );\n\n progress.stop();\n\n // 7. Display success\n console.log(\"\\n\");\n clack.log.success(pc.green(\"Test SMS sent successfully!\"));\n console.log(\"\");\n\n clack.note(\n [\n `${pc.bold(\"Message ID:\")} ${pc.cyan(messageId || \"unknown\")}`,\n `${pc.bold(\"To:\")} ${pc.cyan(toNumber)}`,\n `${pc.bold(\"Message:\")} ${message}`,\n `${pc.bold(\"Type:\")} ${pc.cyan(smsConfig?.phoneNumberType || \"simulator\")}`,\n \"\",\n pc.dim(\n smsConfig?.phoneNumberType === \"simulator\"\n ? \"Note: Simulator messages are not actually delivered\"\n : \"Check your phone for the message!\"\n ),\n ].join(\"\\n\"),\n \"SMS Sent\"\n );\n\n // 8. Show next steps\n if (smsConfig?.eventTracking?.enabled) {\n console.log(\"\");\n clack.log.info(\n pc.dim(\"Event tracking is enabled. Check DynamoDB for delivery status.\")\n );\n }\n\n // 9. Track success\n trackCommand(\"sms:test\", {\n success: true,\n phone_type: smsConfig?.phoneNumberType,\n message_length: message?.length,\n duration_ms: Date.now() - startTime,\n });\n\n clack.outro(pc.green(\"Test complete!\"));\n } catch (error: unknown) {\n progress.stop();\n\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n trackError(\"SMS_SEND_FAILED\", \"sms:test\", { error: errorMessage });\n trackCommand(\"sms:test\", {\n success: false,\n error: errorMessage,\n duration_ms: Date.now() - startTime,\n });\n\n // Handle specific error cases\n if (errorMessage.includes(\"not verified\")) {\n clack.log.error(\"Toll-free number registration is not complete\");\n console.log(\n `\\nRun ${pc.cyan(\"wraps sms register\")} to complete registration.\\n`\n );\n } else if (errorMessage.includes(\"opt-out\")) {\n clack.log.error(\"Destination number has opted out of messages\");\n } else if (errorMessage.includes(\"spending limit\")) {\n clack.log.error(\"AWS SMS spending limit reached\");\n console.log(\"\\nVisit the AWS console to increase your spending limit.\\n\");\n } else {\n clack.log.error(`Failed to send SMS: ${errorMessage}`);\n }\n\n process.exit(1);\n }\n}\n","import * as clack from \"@clack/prompts\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport pc from \"picocolors\";\nimport {\n createSMSEventDestinationWithSDK,\n createSMSPhonePoolWithSDK,\n createSMSProtectConfigurationWithSDK,\n deploySMSStack,\n} from \"../../infrastructure/sms-stack.js\";\nimport { trackError, trackServiceUpgrade } from \"../../telemetry/events.js\";\nimport type {\n SMSStackConfig,\n SMSUpgradeOptions,\n WrapsSMSConfig,\n} from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { errors } from \"../../utils/shared/errors.js\";\nimport {\n ensurePulumiWorkDir,\n getPulumiWorkDir,\n} from \"../../utils/shared/fs.js\";\nimport {\n loadConnectionMetadata,\n saveConnectionMetadata,\n updateServiceConfig,\n} from \"../../utils/shared/metadata.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\nimport { promptVercelConfig } from \"../../utils/shared/prompts.js\";\nimport { ensurePulumiInstalled } from \"../../utils/shared/pulumi.js\";\nimport {\n calculateSMSCosts,\n formatCost,\n getSMSCostSummary,\n} from \"../../utils/sms/costs.js\";\nimport { getAllSMSPresetInfo, getSMSPreset } from \"../../utils/sms/presets.js\";\n\n/**\n * SMS Upgrade command - Enhance existing SMS infrastructure\n */\nexport async function smsUpgrade(options: SMSUpgradeOptions): Promise<void> {\n const startTime = Date.now();\n let upgradeAction: string | symbol = \"\";\n\n clack.intro(pc.bold(\"Wraps SMS Upgrade - Enhance Your SMS Infrastructure\"));\n\n const progress = new DeploymentProgress();\n\n // 1. Check Pulumi CLI is installed\n const wasAutoInstalled = await progress.execute(\n \"Checking Pulumi CLI installation\",\n async () => await ensurePulumiInstalled()\n );\n\n if (wasAutoInstalled) {\n progress.info(\"Pulumi CLI was automatically installed\");\n }\n\n // 2. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n progress.info(`Connected to AWS account: ${pc.cyan(identity.accountId)}`);\n\n // 3. Get region\n let region = options.region;\n if (!region) {\n const defaultRegion = await getAWSRegion();\n region = defaultRegion;\n }\n\n // 4. Load existing connection metadata\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n\n if (!metadata) {\n clack.log.error(\n `No Wraps connection found for account ${pc.cyan(identity.accountId)} in region ${pc.cyan(region)}`\n );\n clack.log.info(\n `Use ${pc.cyan(\"wraps sms init\")} to create new infrastructure.`\n );\n process.exit(1);\n }\n\n if (!metadata.services.sms) {\n clack.log.error(\"No SMS infrastructure found\");\n clack.log.info(\n `Use ${pc.cyan(\"wraps sms init\")} to deploy SMS infrastructure.`\n );\n process.exit(1);\n }\n\n progress.info(`Found existing connection created: ${metadata.timestamp}`);\n\n // 5. Display current configuration\n console.log(`\\n${pc.bold(\"Current Configuration:\")}\\n`);\n\n if (metadata.services.sms.preset) {\n console.log(` Preset: ${pc.cyan(metadata.services.sms.preset)}`);\n } else {\n console.log(` Preset: ${pc.cyan(\"custom\")}`);\n }\n\n const config = metadata.services.sms.config;\n\n if (!config) {\n clack.log.error(\"No SMS configuration found in metadata\");\n clack.log.info(\n `Use ${pc.cyan(\"wraps sms init\")} to create new infrastructure.`\n );\n process.exit(1);\n }\n\n // Show phone number type\n if (config.phoneNumberType) {\n const phoneTypeLabels: Record<string, string> = {\n simulator: \"Simulator ($1/mo, testing only)\",\n \"toll-free\": \"Toll-free ($2/mo, 3 MPS)\",\n \"10dlc\": \"10DLC ($2/mo + fees, 75 MPS)\",\n \"short-code\": \"Short code ($995+/mo, 100+ MPS)\",\n };\n console.log(\n ` Phone Type: ${pc.cyan(phoneTypeLabels[config.phoneNumberType] || config.phoneNumberType)}`\n );\n }\n\n if (config.tracking?.enabled) {\n console.log(` ${pc.green(\"✓\")} Delivery Tracking`);\n if (config.tracking.linkTracking) {\n console.log(` ${pc.dim(\"└─\")} Link click tracking enabled`);\n }\n }\n\n if (config.eventTracking?.enabled) {\n console.log(` ${pc.green(\"✓\")} Event Tracking (SNS)`);\n if (config.eventTracking.dynamoDBHistory) {\n console.log(\n ` ${pc.dim(\"└─\")} Message History: ${pc.cyan(config.eventTracking.archiveRetention || \"90days\")}`\n );\n }\n }\n\n if (config.messageArchiving?.enabled) {\n console.log(\n ` ${pc.green(\"✓\")} Message Archiving (${config.messageArchiving.retention})`\n );\n }\n\n if (config.optOutManagement) {\n console.log(` ${pc.green(\"✓\")} Opt-out Management`);\n }\n\n if (config.protectConfiguration?.enabled) {\n const countries =\n config.protectConfiguration.allowedCountries?.join(\", \") || \"US\";\n console.log(` ${pc.green(\"✓\")} Fraud Protection`);\n console.log(` ${pc.dim(\"└─\")} Allowed countries: ${pc.cyan(countries)}`);\n if (config.protectConfiguration.aitFiltering) {\n console.log(` ${pc.dim(\"└─\")} AIT filtering: ${pc.cyan(\"enabled\")}`);\n }\n } else {\n console.log(` ${pc.dim(\"○\")} Fraud Protection (not configured)`);\n }\n\n // Calculate current cost\n const currentCostData = calculateSMSCosts(config, 10_000);\n console.log(\n `\\n Estimated Cost: ${pc.cyan(`~${formatCost(currentCostData.total.monthly)}/mo`)}`\n );\n\n console.log(\"\");\n\n // 6. Prompt for upgrade action\n const phoneTypeLabels: Record<string, string> = {\n simulator: \"Simulator\",\n \"toll-free\": \"Toll-free\",\n \"10dlc\": \"10DLC\",\n \"short-code\": \"Short code\",\n };\n\n upgradeAction = await clack.select({\n message: \"What would you like to do?\",\n options: [\n {\n value: \"phone-number\",\n label: \"Upgrade phone number type\",\n hint: `Current: ${phoneTypeLabels[config.phoneNumberType || \"simulator\"] || config.phoneNumberType}`,\n },\n {\n value: \"preset\",\n label: \"Upgrade to a different preset\",\n hint: \"Starter → Production → Enterprise\",\n },\n {\n value: \"event-tracking\",\n label: config.eventTracking?.enabled\n ? \"Change event tracking settings\"\n : \"Enable event tracking\",\n hint: config.eventTracking?.enabled\n ? \"Update retention or disable\"\n : \"Track SMS events with message history\",\n },\n {\n value: \"retention\",\n label: \"Change message history retention\",\n hint: \"7 days, 30 days, 90 days, 6 months, 1 year\",\n },\n {\n value: \"link-tracking\",\n label: config.tracking?.linkTracking\n ? \"Disable link tracking\"\n : \"Enable link tracking\",\n hint: \"Track clicks on links in SMS messages\",\n },\n {\n value: \"archiving\",\n label: config.messageArchiving?.enabled\n ? \"Change message archiving settings\"\n : \"Enable message archiving\",\n hint: \"Store full message content\",\n },\n {\n value: \"protect\",\n label: config.protectConfiguration?.enabled\n ? \"Change fraud protection settings\"\n : \"Enable fraud protection\",\n hint: \"Block countries, AIT filtering\",\n },\n ],\n });\n\n if (clack.isCancel(upgradeAction)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n let updatedConfig: WrapsSMSConfig = { ...config };\n let newPreset: string | undefined = metadata.services.sms.preset;\n\n // 7. Handle upgrade action\n switch (upgradeAction) {\n case \"phone-number\": {\n const currentType = config.phoneNumberType || \"simulator\";\n\n // Build available phone types (exclude current and lower tiers)\n const phoneTypes = [\n {\n value: \"simulator\",\n label: \"Simulator - Testing only\",\n hint: \"$1/mo, 100 msg/day limit, no real delivery\",\n tier: 0,\n },\n {\n value: \"toll-free\",\n label: \"Toll-free - Production ready\",\n hint: \"$2/mo, 3 MPS, requires registration\",\n tier: 1,\n },\n {\n value: \"10dlc\",\n label: \"10DLC - High volume\",\n hint: \"$2/mo + campaign fees, up to 75 MPS\",\n tier: 2,\n },\n {\n value: \"short-code\",\n label: \"Short code - Enterprise\",\n hint: \"$995+/mo, 100+ MPS, separate application\",\n tier: 3,\n },\n ];\n\n const currentTier =\n phoneTypes.find((p) => p.value === currentType)?.tier || 0;\n\n const availableTypes = phoneTypes\n .filter((p) => p.tier > currentTier)\n .map((p) => ({\n value: p.value,\n label: p.label,\n hint: p.hint,\n }));\n\n if (availableTypes.length === 0) {\n clack.log.warn(\n \"Already on highest phone number tier. Contact AWS for dedicated short codes.\"\n );\n process.exit(0);\n }\n\n const selectedType = await clack.select({\n message: \"Select new phone number type:\",\n options: availableTypes,\n });\n\n if (clack.isCancel(selectedType)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n // Show warnings for toll-free\n if (selectedType === \"toll-free\") {\n console.log(\n `\\n${pc.yellow(\"⚠\")} ${pc.bold(\"Toll-free Registration Required\")}\\n`\n );\n console.log(\n pc.dim(\"Toll-free numbers require carrier registration before\")\n );\n console.log(\n pc.dim(\"they can send messages at scale. After deployment:\\n\")\n );\n console.log(\n ` 1. Run ${pc.cyan(\"wraps sms register\")} to start registration`\n );\n console.log(\" 2. Submit your business use case information\");\n console.log(\" 3. Wait for carrier verification (1-5 business days)\");\n console.log(\n pc.dim(\"\\nUntil verified, sending is limited to low volume.\\n\")\n );\n\n const confirmTollFree = await clack.confirm({\n message: \"Continue with toll-free number request?\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirmTollFree) || !confirmTollFree) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n }\n\n // Show warnings for 10DLC\n if (selectedType === \"10dlc\") {\n console.log(\n `\\n${pc.yellow(\"⚠\")} ${pc.bold(\"10DLC Campaign Registration Required\")}\\n`\n );\n console.log(pc.dim(\"10DLC requires brand and campaign registration:\"));\n console.log(\" • Brand registration: one-time $4 fee\");\n console.log(\" • Campaign registration: $15/mo per campaign\");\n console.log(\" • Verification takes 1-7 business days\");\n console.log(\"\");\n\n const confirm10DLC = await clack.confirm({\n message: \"Continue with 10DLC number request?\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirm10DLC) || !confirm10DLC) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n }\n\n updatedConfig = {\n ...config,\n phoneNumberType: selectedType as any,\n phoneNumber: undefined, // Will be assigned new number\n };\n newPreset = undefined;\n break;\n }\n\n case \"preset\": {\n const presets = getAllSMSPresetInfo();\n const currentPresetIdx = presets.findIndex(\n (p) => p.name.toLowerCase() === metadata.services.sms?.preset\n );\n\n const availablePresets = presets\n .map((p, idx) => ({\n value: p.name.toLowerCase(),\n label: `${p.name} - ${p.description}`,\n hint: `${p.throughput} | Est. ${p.estimatedCost}`,\n disabled:\n currentPresetIdx >= 0 && idx <= currentPresetIdx\n ? \"Current or lower tier\"\n : undefined,\n }))\n .filter((p) => !p.disabled && p.value !== \"custom\");\n\n if (availablePresets.length === 0) {\n clack.log.warn(\"Already on highest preset (Enterprise)\");\n process.exit(0);\n }\n\n const selectedPreset = await clack.select({\n message: \"Select new preset:\",\n options: availablePresets,\n });\n\n if (clack.isCancel(selectedPreset)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n const presetConfig = getSMSPreset(selectedPreset as any);\n if (presetConfig) {\n // Preserve phone number type if already set (e.g., toll-free shouldn't downgrade to simulator)\n updatedConfig = {\n ...presetConfig,\n phoneNumberType:\n config.phoneNumberType || presetConfig.phoneNumberType,\n phoneNumber: config.phoneNumber,\n };\n }\n newPreset = selectedPreset as string;\n break;\n }\n\n case \"event-tracking\": {\n if (config.eventTracking?.enabled) {\n const eventAction = await clack.select({\n message: \"What would you like to do with event tracking?\",\n options: [\n {\n value: \"change-retention\",\n label: \"Change retention period\",\n hint: `Current: ${config.eventTracking.archiveRetention || \"90days\"}`,\n },\n {\n value: \"disable\",\n label: \"Disable event tracking\",\n hint: \"Stop tracking SMS events\",\n },\n ],\n });\n\n if (clack.isCancel(eventAction)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n if (eventAction === \"disable\") {\n const confirmDisable = await clack.confirm({\n message:\n \"Are you sure? Existing history will remain, but new events won't be tracked.\",\n initialValue: false,\n });\n\n if (clack.isCancel(confirmDisable) || !confirmDisable) {\n clack.cancel(\"Event tracking not disabled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n eventTracking: {\n enabled: false,\n },\n };\n } else {\n const retention = await clack.select({\n message: \"Message history retention period:\",\n options: [\n { value: \"7days\", label: \"7 days\", hint: \"Minimal storage cost\" },\n {\n value: \"30days\",\n label: \"30 days\",\n hint: \"Development/testing\",\n },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"Standard retention\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"Extended retention\",\n },\n {\n value: \"1year\",\n label: \"1 year\",\n hint: \"Compliance requirements\",\n },\n ],\n initialValue: config.eventTracking.archiveRetention || \"90days\",\n });\n\n if (clack.isCancel(retention)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n eventTracking: {\n ...config.eventTracking,\n archiveRetention: retention as any,\n },\n };\n }\n } else {\n const enableTracking = await clack.confirm({\n message: \"Enable event tracking? (Track SMS events with history)\",\n initialValue: true,\n });\n\n if (clack.isCancel(enableTracking)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n if (!enableTracking) {\n clack.log.info(\"Event tracking not enabled.\");\n process.exit(0);\n }\n\n const retention = await clack.select({\n message: \"Message history retention period:\",\n options: [\n { value: \"7days\", label: \"7 days\", hint: \"Minimal storage cost\" },\n { value: \"30days\", label: \"30 days\", hint: \"Development/testing\" },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"Standard retention\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"Extended retention\",\n },\n {\n value: \"1year\",\n label: \"1 year\",\n hint: \"Compliance requirements\",\n },\n ],\n initialValue: \"90days\",\n });\n\n if (clack.isCancel(retention)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n eventTracking: {\n enabled: true,\n eventBridge: true,\n events: [\"SENT\", \"DELIVERED\", \"FAILED\", \"OPTED_OUT\"],\n dynamoDBHistory: true,\n archiveRetention: retention as any,\n },\n };\n }\n newPreset = undefined;\n break;\n }\n\n case \"retention\": {\n if (!config.eventTracking?.enabled) {\n clack.log.error(\n \"Event tracking is not enabled. Enable it first to change retention.\"\n );\n process.exit(1);\n }\n\n const retention = await clack.select({\n message: \"Message history retention period (event data in DynamoDB):\",\n options: [\n { value: \"7days\", label: \"7 days\", hint: \"Minimal storage cost\" },\n { value: \"30days\", label: \"30 days\", hint: \"Development/testing\" },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"Standard retention\",\n },\n { value: \"6months\", label: \"6 months\", hint: \"Extended retention\" },\n {\n value: \"1year\",\n label: \"1 year\",\n hint: \"Compliance requirements\",\n },\n ],\n initialValue: config.eventTracking.archiveRetention || \"90days\",\n });\n\n if (clack.isCancel(retention)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n eventTracking: {\n ...config.eventTracking,\n enabled: true,\n dynamoDBHistory: true,\n archiveRetention: retention as any,\n },\n };\n newPreset = undefined;\n break;\n }\n\n case \"link-tracking\": {\n const enableLinkTracking = !config.tracking?.linkTracking;\n\n if (enableLinkTracking) {\n clack.log.info(\n pc.dim(\n \"Link tracking will track clicks on URLs in your SMS messages.\"\n )\n );\n clack.log.info(\n pc.dim(\"URLs will be rewritten to go through a tracking endpoint.\")\n );\n }\n\n const confirmed = await clack.confirm({\n message: enableLinkTracking\n ? \"Enable link click tracking?\"\n : \"Disable link click tracking?\",\n initialValue: enableLinkTracking,\n });\n\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n tracking: {\n ...config.tracking,\n enabled: true,\n deliveryReports: config.tracking?.deliveryReports ?? true,\n linkTracking: enableLinkTracking,\n },\n };\n newPreset = undefined;\n break;\n }\n\n case \"archiving\": {\n if (config.messageArchiving?.enabled) {\n const archivingAction = await clack.select({\n message: \"What would you like to do with message archiving?\",\n options: [\n {\n value: \"change-retention\",\n label: \"Change retention period\",\n hint: `Current: ${config.messageArchiving.retention}`,\n },\n {\n value: \"disable\",\n label: \"Disable message archiving\",\n hint: \"Stop storing full message content\",\n },\n ],\n });\n\n if (clack.isCancel(archivingAction)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n if (archivingAction === \"disable\") {\n const confirmDisable = await clack.confirm({\n message:\n \"Are you sure? Existing archived messages will remain, but new messages won't be archived.\",\n initialValue: false,\n });\n\n if (clack.isCancel(confirmDisable) || !confirmDisable) {\n clack.cancel(\"Archiving not disabled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n messageArchiving: {\n enabled: false,\n retention: config.messageArchiving.retention,\n },\n };\n } else {\n const retention = await clack.select({\n message: \"Message archive retention period:\",\n options: [\n {\n value: \"7days\",\n label: \"7 days\",\n hint: \"~$1-2/mo for 10k msgs\",\n },\n {\n value: \"30days\",\n label: \"30 days\",\n hint: \"~$2-4/mo for 10k msgs\",\n },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"~$5-10/mo for 10k msgs\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"~$15-25/mo for 10k msgs\",\n },\n {\n value: \"1year\",\n label: \"1 year\",\n hint: \"~$25-40/mo for 10k msgs\",\n },\n ],\n initialValue: config.messageArchiving.retention,\n });\n\n if (clack.isCancel(retention)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n messageArchiving: {\n enabled: true,\n retention: retention as any,\n },\n };\n }\n } else {\n const enableArchiving = await clack.confirm({\n message:\n \"Enable message archiving? (Store full message content for viewing)\",\n initialValue: true,\n });\n\n if (clack.isCancel(enableArchiving)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n if (!enableArchiving) {\n clack.log.info(\"Message archiving not enabled.\");\n process.exit(0);\n }\n\n const retention = await clack.select({\n message: \"Message archive retention period:\",\n options: [\n { value: \"7days\", label: \"7 days\", hint: \"~$1-2/mo for 10k msgs\" },\n {\n value: \"30days\",\n label: \"30 days\",\n hint: \"~$2-4/mo for 10k msgs\",\n },\n {\n value: \"90days\",\n label: \"90 days (recommended)\",\n hint: \"~$5-10/mo for 10k msgs\",\n },\n {\n value: \"6months\",\n label: \"6 months\",\n hint: \"~$15-25/mo for 10k msgs\",\n },\n {\n value: \"1year\",\n label: \"1 year\",\n hint: \"~$25-40/mo for 10k msgs\",\n },\n ],\n initialValue: \"90days\",\n });\n\n if (clack.isCancel(retention)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n messageArchiving: {\n enabled: true,\n retention: retention as any,\n },\n };\n }\n newPreset = undefined;\n break;\n }\n\n case \"protect\": {\n // Common countries for selection\n const commonCountries = [\n { code: \"US\", name: \"United States\" },\n { code: \"CA\", name: \"Canada\" },\n { code: \"GB\", name: \"United Kingdom\" },\n { code: \"AU\", name: \"Australia\" },\n { code: \"DE\", name: \"Germany\" },\n { code: \"FR\", name: \"France\" },\n { code: \"ES\", name: \"Spain\" },\n { code: \"IT\", name: \"Italy\" },\n { code: \"NL\", name: \"Netherlands\" },\n { code: \"BR\", name: \"Brazil\" },\n { code: \"MX\", name: \"Mexico\" },\n { code: \"IN\", name: \"India\" },\n ];\n\n // Select allowed countries\n const currentAllowed = config.protectConfiguration?.allowedCountries || [\n \"US\",\n ];\n const selectedCountries = await clack.multiselect({\n message: \"Select countries to allow SMS delivery (all others blocked):\",\n options: commonCountries.map((c) => ({\n value: c.code,\n label: `${c.name} (${c.code})`,\n })),\n initialValues: currentAllowed,\n required: true,\n });\n\n if (clack.isCancel(selectedCountries)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n // Ask about AIT filtering\n const enableAIT = await clack.confirm({\n message:\n \"Enable AIT (Artificially Inflated Traffic) filtering? (adds per-message cost)\",\n initialValue: config.protectConfiguration?.aitFiltering ?? false,\n });\n\n if (clack.isCancel(enableAIT)) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n\n updatedConfig = {\n ...config,\n protectConfiguration: {\n enabled: true,\n allowedCountries: selectedCountries as string[],\n aitFiltering: enableAIT,\n },\n };\n newPreset = undefined;\n break;\n }\n }\n\n // 8. Show cost comparison\n const newCostData = calculateSMSCosts(updatedConfig, 10_000);\n const costDiff = newCostData.total.monthly - currentCostData.total.monthly;\n\n console.log(`\\n${pc.bold(\"Cost Impact:\")}`);\n console.log(\n ` Current: ${pc.cyan(`${formatCost(currentCostData.total.monthly)}/mo`)}`\n );\n console.log(\n ` New: ${pc.cyan(`${formatCost(newCostData.total.monthly)}/mo`)}`\n );\n if (costDiff > 0) {\n console.log(` Change: ${pc.yellow(`+${formatCost(costDiff)}/mo`)}`);\n } else if (costDiff < 0) {\n console.log(\n ` Change: ${pc.green(`-${formatCost(Math.abs(costDiff))}/mo`)}`\n );\n }\n console.log(\"\");\n\n // 9. Confirm upgrade\n if (!options.yes) {\n const confirmed = await clack.confirm({\n message: \"Proceed with upgrade?\",\n initialValue: true,\n });\n\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel(\"Upgrade cancelled.\");\n process.exit(0);\n }\n }\n\n // 10. Get Vercel config if needed and not already stored\n let vercelConfig;\n if (metadata.provider === \"vercel\" && !metadata.vercel) {\n vercelConfig = await promptVercelConfig();\n } else if (metadata.provider === \"vercel\") {\n vercelConfig = metadata.vercel;\n }\n\n // 11. Build stack configuration\n const stackConfig: SMSStackConfig = {\n provider: metadata.provider,\n region,\n vercel: vercelConfig,\n smsConfig: updatedConfig,\n };\n\n // 12. Update Pulumi stack\n let outputs: {\n roleArn: string;\n phoneNumber: string | undefined;\n phoneNumberArn: string | undefined;\n configSetName: string | undefined;\n tableName: string | undefined;\n region: string;\n lambdaFunctions: string[] | undefined;\n snsTopicArn: string | undefined;\n queueUrl: string | undefined;\n dlqUrl: string | undefined;\n optOutListArn: string | undefined;\n };\n try {\n outputs = await progress.execute(\n \"Updating SMS infrastructure (this may take 2-3 minutes)\",\n async () => {\n await ensurePulumiWorkDir();\n\n const stack =\n await pulumi.automation.LocalWorkspace.createOrSelectStack(\n {\n stackName:\n metadata.services.sms?.pulumiStackName ||\n `wraps-sms-${identity.accountId}-${region}`,\n projectName: \"wraps-sms\",\n program: async () => {\n const result = await deploySMSStack(stackConfig);\n return {\n roleArn: result.roleArn,\n phoneNumber: result.phoneNumber,\n phoneNumberArn: result.phoneNumberArn,\n configSetName: result.configSetName,\n tableName: result.tableName,\n region: result.region,\n lambdaFunctions: result.lambdaFunctions,\n snsTopicArn: result.snsTopicArn,\n queueUrl: result.queueUrl,\n dlqUrl: result.dlqUrl,\n optOutListArn: result.optOutListArn,\n };\n },\n },\n {\n workDir: getPulumiWorkDir(),\n envVars: {\n PULUMI_CONFIG_PASSPHRASE: \"\",\n AWS_REGION: region,\n },\n secretsProvider: \"passphrase\",\n }\n );\n\n await stack.workspace.selectStack(\n metadata.services.sms?.pulumiStackName ||\n `wraps-sms-${identity.accountId}-${region}`\n );\n await stack.setConfig(\"aws:region\", { value: region });\n\n // Refresh state to sync with AWS before upgrading\n await stack.refresh({ onOutput: () => {} });\n\n // Pulumi will automatically detect changes and only update what's needed\n const upResult = await stack.up({ onOutput: () => {} });\n const pulumiOutputs = upResult.outputs;\n\n return {\n roleArn: pulumiOutputs.roleArn?.value as string,\n phoneNumber: pulumiOutputs.phoneNumber?.value as string | undefined,\n phoneNumberArn: pulumiOutputs.phoneNumberArn?.value as\n | string\n | undefined,\n configSetName: pulumiOutputs.configSetName?.value as\n | string\n | undefined,\n tableName: pulumiOutputs.tableName?.value as string | undefined,\n region: pulumiOutputs.region?.value as string,\n lambdaFunctions: pulumiOutputs.lambdaFunctions?.value as\n | string[]\n | undefined,\n snsTopicArn: pulumiOutputs.snsTopicArn?.value as string | undefined,\n queueUrl: pulumiOutputs.queueUrl?.value as string | undefined,\n dlqUrl: pulumiOutputs.dlqUrl?.value as string | undefined,\n optOutListArn: pulumiOutputs.optOutListArn?.value as\n | string\n | undefined,\n };\n }\n );\n\n // 12a. Create phone pool via SDK (after Pulumi deployment)\n if (outputs.phoneNumberArn) {\n await progress.execute(\"Creating phone pool\", async () => {\n await createSMSPhonePoolWithSDK(outputs.phoneNumberArn!, region);\n });\n }\n\n // 12b. Create event destination via SDK (after Pulumi deployment)\n if (\n updatedConfig.eventTracking?.enabled &&\n outputs.configSetName &&\n outputs.snsTopicArn\n ) {\n await progress.execute(\"Configuring event destination\", async () => {\n await createSMSEventDestinationWithSDK(\n outputs.configSetName!,\n outputs.snsTopicArn!,\n region\n );\n });\n }\n\n // 12c. Update protect configuration via SDK\n if (updatedConfig.protectConfiguration?.enabled && outputs.configSetName) {\n await progress.execute(\"Updating fraud protection\", async () => {\n await createSMSProtectConfigurationWithSDK(\n outputs.configSetName!,\n region,\n {\n allowedCountries:\n updatedConfig.protectConfiguration?.allowedCountries,\n aitFiltering: updatedConfig.protectConfiguration?.aitFiltering,\n }\n );\n });\n }\n } catch (error: any) {\n trackServiceUpgrade(\"sms\", {\n from_preset: metadata.services.sms?.preset,\n to_preset: newPreset,\n action: typeof upgradeAction === \"string\" ? upgradeAction : undefined,\n duration_ms: Date.now() - startTime,\n });\n\n if (error.message?.includes(\"stack is currently locked\")) {\n trackError(\"STACK_LOCKED\", \"sms:upgrade\", { step: \"deploy\" });\n throw errors.stackLocked();\n }\n\n trackError(\"UPGRADE_FAILED\", \"sms:upgrade\", { step: \"deploy\" });\n throw new Error(`SMS upgrade failed: ${error.message}`);\n }\n\n // 13. Update metadata\n updateServiceConfig(metadata, \"sms\", updatedConfig);\n if (metadata.services.sms) {\n metadata.services.sms.preset = newPreset as any;\n }\n await saveConnectionMetadata(metadata);\n\n progress.info(\"Connection metadata updated\");\n\n // 14. Display success message\n console.log(\"\\n\");\n clack.log.success(pc.green(pc.bold(\"SMS infrastructure upgraded!\")));\n console.log(\"\\n\");\n\n // Show updated resources\n clack.note(\n [\n `${pc.bold(\"Phone Number:\")} ${pc.cyan(outputs.phoneNumber || \"Provisioning...\")}`,\n `${pc.bold(\"Phone Type:\")} ${pc.cyan(updatedConfig.phoneNumberType || \"simulator\")}`,\n `${pc.bold(\"Config Set:\")} ${pc.cyan(outputs.configSetName || \"wraps-sms-config\")}`,\n `${pc.bold(\"Region:\")} ${pc.cyan(outputs.region)}`,\n outputs.tableName\n ? `${pc.bold(\"History Table:\")} ${pc.cyan(outputs.tableName)}`\n : \"\",\n \"\",\n pc.dim(\"IAM Role:\"),\n pc.dim(` ${outputs.roleArn}`),\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n \"SMS Infrastructure\"\n );\n\n // Show what was upgraded\n console.log(`\\n${pc.green(\"✓\")} ${pc.bold(\"Upgrade complete!\")}\\n`);\n\n if (upgradeAction === \"phone-number\") {\n console.log(\n `Upgraded to ${pc.cyan(updatedConfig.phoneNumberType)} number (${pc.green(`${formatCost(newCostData.total.monthly)}/mo`)})\\n`\n );\n\n // Show next steps for toll-free registration\n if (updatedConfig.phoneNumberType === \"toll-free\") {\n console.log(`${pc.bold(\"Next Steps:\")}`);\n console.log(\n ` 1. Run ${pc.cyan(\"wraps sms register\")} to start toll-free registration`\n );\n console.log(\" 2. Submit your business information and use case\");\n console.log(\" 3. Wait for carrier verification (1-5 business days)\");\n console.log(\"\");\n console.log(\n pc.dim(\"Until verified, your number can only send limited messages.\")\n );\n console.log(\"\");\n } else if (updatedConfig.phoneNumberType === \"10dlc\") {\n console.log(`${pc.bold(\"Next Steps:\")}`);\n console.log(\" 1. Register your brand in the AWS Console\");\n console.log(\" 2. Create a 10DLC campaign for your use case\");\n console.log(\" 3. Wait for campaign approval (1-7 business days)\");\n console.log(\"\");\n }\n } else if (upgradeAction === \"preset\" && newPreset) {\n console.log(\n `Upgraded to ${pc.cyan(newPreset)} preset (${pc.green(`${formatCost(newCostData.total.monthly)}/mo`)})\\n`\n );\n } else {\n console.log(\n `Updated configuration (${pc.green(`${formatCost(newCostData.total.monthly)}/mo`)})\\n`\n );\n }\n\n // Show cost summary\n console.log(pc.dim(getSMSCostSummary(updatedConfig, 10_000)));\n\n // 15. Track successful upgrade\n const enabledFeatures: string[] = [];\n if (updatedConfig.tracking?.enabled) enabledFeatures.push(\"tracking\");\n if (updatedConfig.tracking?.linkTracking)\n enabledFeatures.push(\"link_tracking\");\n if (updatedConfig.eventTracking?.enabled)\n enabledFeatures.push(\"event_tracking\");\n if (updatedConfig.eventTracking?.dynamoDBHistory)\n enabledFeatures.push(\"dynamodb_history\");\n if (updatedConfig.messageArchiving?.enabled)\n enabledFeatures.push(\"message_archiving\");\n\n trackServiceUpgrade(\"sms\", {\n from_preset: metadata.services.sms?.preset,\n to_preset: newPreset,\n added_features: enabledFeatures,\n action: typeof upgradeAction === \"string\" ? upgradeAction : undefined,\n duration_ms: Date.now() - startTime,\n });\n\n clack.outro(pc.green(\"Upgrade complete!\"));\n}\n","import {\n CreateVerifiedDestinationNumberCommand,\n DeleteVerifiedDestinationNumberCommand,\n DescribeVerifiedDestinationNumbersCommand,\n PinpointSMSVoiceV2Client,\n SendDestinationNumberVerificationCodeCommand,\n VerifyDestinationNumberCommand,\n} from \"@aws-sdk/client-pinpoint-sms-voice-v2\";\nimport * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { trackCommand, trackError } from \"../../telemetry/events.js\";\nimport type { SMSVerifyNumberOptions } from \"../../types/index.js\";\nimport {\n getAWSRegion,\n validateAWSCredentials,\n} from \"../../utils/shared/aws.js\";\nimport { loadConnectionMetadata } from \"../../utils/shared/metadata.js\";\nimport { DeploymentProgress } from \"../../utils/shared/output.js\";\n\n/**\n * Validate phone number format (E.164)\n */\nfunction isValidPhoneNumber(phone: string): boolean {\n return /^\\+[1-9]\\d{1,14}$/.test(phone);\n}\n\n/**\n * SMS Verify Number command - Verify a destination phone number for sandbox testing\n */\nexport async function smsVerifyNumber(\n options: SMSVerifyNumberOptions\n): Promise<void> {\n const startTime = Date.now();\n const progress = new DeploymentProgress();\n\n clack.intro(pc.bold(\"Wraps SMS - Verify Destination Number\"));\n\n // 1. Validate AWS credentials\n const identity = await progress.execute(\n \"Validating AWS credentials\",\n async () => validateAWSCredentials()\n );\n\n // 2. Get region\n const region = await getAWSRegion();\n\n // 3. Check for existing metadata\n const metadata = await loadConnectionMetadata(identity.accountId, region);\n\n if (!metadata?.services?.sms) {\n progress.stop();\n clack.log.error(\"No SMS infrastructure found\");\n console.log(\n `\\nRun ${pc.cyan(\"wraps sms init\")} to deploy SMS infrastructure.\\n`\n );\n process.exit(1);\n }\n\n const client = new PinpointSMSVoiceV2Client({ region });\n\n // Handle --list flag\n if (options.list) {\n try {\n const response = await progress.execute(\n \"Fetching verified numbers\",\n async () =>\n client.send(new DescribeVerifiedDestinationNumbersCommand({}))\n );\n\n progress.stop();\n\n if (\n !response.VerifiedDestinationNumbers ||\n response.VerifiedDestinationNumbers.length === 0\n ) {\n clack.log.info(\"No verified destination numbers found\");\n console.log(\n `\\nRun ${pc.cyan(\"wraps sms verify-number\")} to verify a number.\\n`\n );\n } else {\n console.log(\"\\n\");\n clack.log.info(pc.bold(\"Verified Destination Numbers:\"));\n console.log(\"\");\n for (const num of response.VerifiedDestinationNumbers) {\n const status =\n num.Status === \"VERIFIED\"\n ? pc.green(\"✓ Verified\")\n : pc.yellow(\"⧖ Pending\");\n console.log(` ${pc.cyan(num.DestinationPhoneNumber)} - ${status}`);\n }\n console.log(\"\");\n }\n\n trackCommand(\"sms:verify-number:list\", {\n success: true,\n count: response.VerifiedDestinationNumbers?.length || 0,\n duration_ms: Date.now() - startTime,\n });\n\n clack.outro(pc.green(\"Done!\"));\n return;\n } catch (error: unknown) {\n progress.stop();\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n trackError(\"SMS_LIST_VERIFIED_FAILED\", \"sms:verify-number:list\", {\n error: errorMessage,\n });\n clack.log.error(`Failed to list verified numbers: ${errorMessage}`);\n process.exit(1);\n }\n }\n\n // Handle --delete flag\n if (options.delete) {\n const phoneNumber = options.phoneNumber;\n if (!phoneNumber) {\n progress.stop();\n clack.log.error(\"Phone number is required for deletion\");\n console.log(\n `\\nUsage: ${pc.cyan(\"wraps sms verify-number --delete --phone-number +14155551234\")}\\n`\n );\n process.exit(1);\n }\n\n try {\n // First find the verified destination number ID\n const listResponse = await client.send(\n new DescribeVerifiedDestinationNumbersCommand({\n DestinationPhoneNumbers: [phoneNumber],\n })\n );\n\n const verifiedNumber = listResponse.VerifiedDestinationNumbers?.[0];\n if (!verifiedNumber?.VerifiedDestinationNumberId) {\n progress.stop();\n clack.log.error(`Number ${phoneNumber} is not in verified list`);\n process.exit(1);\n }\n\n await progress.execute(`Removing ${phoneNumber}`, async () => {\n await client.send(\n new DeleteVerifiedDestinationNumberCommand({\n VerifiedDestinationNumberId:\n verifiedNumber.VerifiedDestinationNumberId,\n })\n );\n });\n\n progress.stop();\n clack.log.success(`Removed ${pc.cyan(phoneNumber)} from verified list`);\n\n trackCommand(\"sms:verify-number:delete\", {\n success: true,\n duration_ms: Date.now() - startTime,\n });\n\n clack.outro(pc.green(\"Done!\"));\n return;\n } catch (error: unknown) {\n progress.stop();\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n trackError(\"SMS_DELETE_VERIFIED_FAILED\", \"sms:verify-number:delete\", {\n error: errorMessage,\n });\n clack.log.error(`Failed to delete verified number: ${errorMessage}`);\n process.exit(1);\n }\n }\n\n // Main flow: verify a new number\n let phoneNumber = options.phoneNumber;\n if (!phoneNumber) {\n const result = await clack.text({\n message: \"Enter phone number to verify (E.164 format):\",\n placeholder: \"+14155551234\",\n validate: (value) => {\n if (!value) return \"Phone number is required\";\n if (!isValidPhoneNumber(value)) {\n return \"Please enter a valid phone number in E.164 format (e.g., +14155551234)\";\n }\n return;\n },\n });\n\n if (clack.isCancel(result)) {\n clack.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n phoneNumber = result;\n } else if (!isValidPhoneNumber(phoneNumber)) {\n progress.stop();\n clack.log.error(\n `Invalid phone number format: ${phoneNumber}. Use E.164 format (e.g., +14155551234)`\n );\n process.exit(1);\n }\n\n // Handle --code flag (completing verification)\n if (options.code) {\n try {\n // First find the verified destination number ID\n const listResponse = await client.send(\n new DescribeVerifiedDestinationNumbersCommand({\n DestinationPhoneNumbers: [phoneNumber],\n })\n );\n\n const verifiedNumber = listResponse.VerifiedDestinationNumbers?.[0];\n if (!verifiedNumber?.VerifiedDestinationNumberId) {\n progress.stop();\n clack.log.error(\n `Number ${phoneNumber} not found. Run without --code first.`\n );\n process.exit(1);\n }\n\n await progress.execute(\"Verifying code\", async () => {\n await client.send(\n new VerifyDestinationNumberCommand({\n VerifiedDestinationNumberId:\n verifiedNumber.VerifiedDestinationNumberId,\n VerificationCode: options.code,\n })\n );\n });\n\n progress.stop();\n\n console.log(\"\\n\");\n clack.log.success(\n pc.green(`Phone number ${pc.cyan(phoneNumber)} verified!`)\n );\n console.log(\"\");\n console.log(\n `You can now send test messages to this number with ${pc.cyan(\"wraps sms test\")}`\n );\n\n trackCommand(\"sms:verify-number:confirm\", {\n success: true,\n duration_ms: Date.now() - startTime,\n });\n\n clack.outro(pc.green(\"Verification complete!\"));\n return;\n } catch (error: unknown) {\n progress.stop();\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n\n if (errorMessage.includes(\"Invalid verification code\")) {\n clack.log.error(\"Invalid verification code. Please try again.\");\n console.log(\n `\\nRun ${pc.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`)} to get a new code.\\n`\n );\n } else {\n trackError(\"SMS_VERIFY_CODE_FAILED\", \"sms:verify-number:confirm\", {\n error: errorMessage,\n });\n clack.log.error(`Verification failed: ${errorMessage}`);\n }\n process.exit(1);\n }\n }\n\n // Handle --resend flag\n if (options.resend) {\n try {\n // Find the verified destination number ID\n const listResponse = await client.send(\n new DescribeVerifiedDestinationNumbersCommand({\n DestinationPhoneNumbers: [phoneNumber],\n })\n );\n\n const verifiedNumber = listResponse.VerifiedDestinationNumbers?.[0];\n if (!verifiedNumber?.VerifiedDestinationNumberId) {\n progress.stop();\n clack.log.error(\n `Number ${phoneNumber} not found. Run without --resend first.`\n );\n process.exit(1);\n }\n\n await progress.execute(`Resending code to ${phoneNumber}`, async () => {\n await client.send(\n new SendDestinationNumberVerificationCodeCommand({\n VerifiedDestinationNumberId:\n verifiedNumber.VerifiedDestinationNumberId,\n VerificationChannel: \"TEXT\",\n })\n );\n });\n\n progress.stop();\n\n clack.log.success(`Verification code resent to ${pc.cyan(phoneNumber)}`);\n console.log(\"\");\n console.log(\n `Once you receive the code, run:\\n ${pc.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --code YOUR_CODE`)}`\n );\n\n trackCommand(\"sms:verify-number:resend\", {\n success: true,\n duration_ms: Date.now() - startTime,\n });\n\n clack.outro(pc.green(\"Code sent!\"));\n return;\n } catch (error: unknown) {\n progress.stop();\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n trackError(\"SMS_RESEND_CODE_FAILED\", \"sms:verify-number:resend\", {\n error: errorMessage,\n });\n clack.log.error(`Failed to resend code: ${errorMessage}`);\n process.exit(1);\n }\n }\n\n // Start new verification\n try {\n // Check if already verified\n const listResponse = await client.send(\n new DescribeVerifiedDestinationNumbersCommand({\n DestinationPhoneNumbers: [phoneNumber],\n })\n );\n\n const existingNumber = listResponse.VerifiedDestinationNumbers?.[0];\n if (existingNumber?.Status === \"VERIFIED\") {\n progress.stop();\n clack.log.info(\n `Number ${pc.cyan(phoneNumber)} is already verified and ready to use!`\n );\n clack.outro(pc.green(\"Done!\"));\n return;\n }\n\n // If pending, just resend the code\n if (existingNumber?.Status === \"PENDING\") {\n await progress.execute(\n `Resending verification code to ${phoneNumber}`,\n async () => {\n await client.send(\n new SendDestinationNumberVerificationCodeCommand({\n VerifiedDestinationNumberId:\n existingNumber.VerifiedDestinationNumberId,\n VerificationChannel: \"TEXT\",\n })\n );\n }\n );\n\n progress.stop();\n\n clack.log.info(\n `Verification already in progress. New code sent to ${pc.cyan(phoneNumber)}`\n );\n console.log(\"\");\n console.log(\n `Once you receive the code, run:\\n ${pc.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --code YOUR_CODE`)}`\n );\n\n clack.outro(pc.green(\"Code sent!\"));\n return;\n }\n\n // Create new verified destination number\n const createResponse = await progress.execute(\n `Creating verification for ${phoneNumber}`,\n async () =>\n client.send(\n new CreateVerifiedDestinationNumberCommand({\n DestinationPhoneNumber: phoneNumber,\n })\n )\n );\n\n // Send verification code\n await progress.execute(\"Sending verification code\", async () => {\n await client.send(\n new SendDestinationNumberVerificationCodeCommand({\n VerifiedDestinationNumberId:\n createResponse.VerifiedDestinationNumberId,\n VerificationChannel: \"TEXT\",\n })\n );\n });\n\n progress.stop();\n\n console.log(\"\\n\");\n clack.log.success(\n `Verification code sent to ${pc.cyan(phoneNumber)} via SMS`\n );\n console.log(\"\");\n\n clack.note(\n [\n \"1. Check your phone for the verification code\",\n \"\",\n \"2. Complete verification with:\",\n ` ${pc.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --code YOUR_CODE`)}`,\n \"\",\n pc.dim(\"The code expires in 24 hours\"),\n ].join(\"\\n\"),\n \"Next Steps\"\n );\n\n trackCommand(\"sms:verify-number:start\", {\n success: true,\n duration_ms: Date.now() - startTime,\n });\n\n clack.outro(pc.green(\"Verification started!\"));\n } catch (error: unknown) {\n progress.stop();\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (errorMessage.includes(\"already exists\")) {\n clack.log.error(\"This number is already being verified\");\n console.log(\n `\\nRun ${pc.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`)} to get a new code.\\n`\n );\n } else {\n trackError(\"SMS_CREATE_VERIFIED_FAILED\", \"sms:verify-number:start\", {\n error: errorMessage,\n });\n clack.log.error(`Failed to start verification: ${errorMessage}`);\n }\n process.exit(1);\n }\n}\n","/**\n * Telemetry management commands\n * @module commands/telemetry\n */\n\nimport * as clack from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { getTelemetryClient } from \"../telemetry/client.js\";\n\n/**\n * Enable telemetry\n */\nexport async function telemetryEnable(): Promise<void> {\n const client = getTelemetryClient();\n\n client.enable();\n\n clack.log.success(pc.green(\"Telemetry enabled\"));\n console.log(` Config: ${pc.dim(client.getConfigPath())}`);\n console.log(`\\n ${pc.dim(\"Thank you for helping improve Wraps!\")}\\n`);\n}\n\n/**\n * Disable telemetry\n */\nexport async function telemetryDisable(): Promise<void> {\n const client = getTelemetryClient();\n\n client.disable();\n\n clack.log.success(pc.green(\"Telemetry disabled\"));\n console.log(` Config: ${pc.dim(client.getConfigPath())}`);\n console.log(\n `\\n ${pc.dim(\"You can re-enable with:\")} wraps telemetry enable\\n`\n );\n}\n\n/**\n * Show telemetry status\n */\nexport async function telemetryStatus(): Promise<void> {\n const client = getTelemetryClient();\n\n clack.intro(pc.bold(\"Telemetry Status\"));\n\n const status = client.isEnabled() ? pc.green(\"Enabled\") : pc.red(\"Disabled\");\n\n console.log();\n console.log(` ${pc.bold(\"Status:\")} ${status}`);\n console.log(` ${pc.bold(\"Config file:\")} ${pc.dim(client.getConfigPath())}`);\n\n // Show opt-out methods\n if (client.isEnabled()) {\n console.log();\n console.log(pc.bold(\" How to opt-out:\"));\n console.log(` ${pc.cyan(\"wraps telemetry disable\")}`);\n console.log(\n ` ${pc.dim(\"Or set:\")} ${pc.cyan(\"WRAPS_TELEMETRY_DISABLED=1\")}`\n );\n console.log(` ${pc.dim(\"Or set:\")} ${pc.cyan(\"DO_NOT_TRACK=1\")}`);\n } else {\n console.log();\n console.log(pc.bold(\" How to opt-in:\"));\n console.log(` ${pc.cyan(\"wraps telemetry enable\")}`);\n }\n\n // Show debug mode info\n console.log();\n console.log(pc.bold(\" Debug mode:\"));\n console.log(\n ` ${pc.dim(\"See what would be sent:\")} ${pc.cyan(\"WRAPS_TELEMETRY_DEBUG=1 wraps <command>\")}`\n );\n\n // Show docs link\n console.log();\n console.log(\n ` ${pc.dim(\"Learn more:\")} ${pc.cyan(\"https://wraps.dev/docs/telemetry\")}`\n );\n console.log();\n}\n","/**\n * Setup tab completion for the Wraps CLI\n *\n * This is a placeholder for future tab completion support.\n * Will integrate with tabtab or similar completion library.\n */\nexport function setupTabCompletion() {\n // Placeholder for tab completion setup\n // Will be implemented in Phase 2\n}\n\n/**\n * Print completion script for the current shell\n */\nexport function printCompletionScript() {\n console.log(\"# Wraps CLI Tab Completion\");\n console.log(\"# ========================\\n\");\n console.log(\"# Tab completion will be available in a future release.\\n\");\n console.log(\"# For now, here are the available commands:\\n\");\n console.log(\"# Email Commands:\");\n console.log(\n \"# wraps email init [--provider vercel|aws|railway|other] [--region <region>] [--domain <domain>]\"\n );\n console.log(\"# wraps email connect [--region <region>]\");\n console.log(\"# wraps email status [--account <account-id>]\");\n console.log(\"# wraps email verify --domain <domain>\");\n console.log(\"# wraps email sync\");\n console.log(\"# wraps email upgrade\");\n console.log(\"# wraps email restore [--region <region>] [--force]\");\n console.log(\"# wraps email destroy [--force] [--preview]\");\n console.log(\"# wraps email domains add --domain <domain>\");\n console.log(\"# wraps email domains list\");\n console.log(\"# wraps email domains verify --domain <domain>\");\n console.log(\"# wraps email domains get-dkim --domain <domain>\");\n console.log(\"# wraps email domains remove --domain <domain> [--force]\\n\");\n console.log(\"# Global Commands:\");\n console.log(\"# wraps status\");\n console.log(\"# wraps destroy [--force] [--preview]\");\n console.log(\"# wraps console [--port <port>] [--no-open]\");\n console.log(\"# wraps completion\");\n console.log(\"# wraps telemetry [enable|disable|status]\\n\");\n console.log(\"# Dashboard Commands:\");\n console.log(\n \"# wraps dashboard update-role [--region <region>] [--force]\\n\"\n );\n console.log(\"# Flags:\");\n console.log(\"# -p, --provider : vercel, aws, railway, other\");\n console.log(\n \"# -r, --region : us-east-1, us-east-2, us-west-1, us-west-2, eu-west-1, eu-west-2, etc.\"\n );\n console.log(\"# -d, --domain : Your domain name (e.g., myapp.com)\");\n console.log(\"# --account : AWS account ID or alias\");\n console.log(\"# --preset : starter, production, enterprise, custom\");\n console.log(\"# -y, --yes : Skip confirmation prompts\");\n console.log(\"# -f, --force : Force destructive operations\");\n console.log(\"# --preview : Preview changes without deploying\\n\");\n}\n"],"mappings":"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","names":["packageJson","acm","existsSync","join","fileURLToPath","aws","pulumi","LambdaClient","lambda","config","status","aws","config","aws","cloudfront","config","config","config","config","clack","pc","config","getAllPresetInfo","STSClient","MailManagerClient","DynamoDBClient","ScanCommand","unmarshall","dynamodb","dirname","join","fileURLToPath","clack","pc","intro","log","outro","pc","existsSync","join","join","existsSync","mkdir","config","clack","pc","status","intro","pc","log","iam","roleExists","outro","clack","pulumi","pc","aws","pulumi","DynamoDBClient","DescribeTableCommand","dynamodb","aws","config","aws","pulumi","IAMClient","GetRoleCommand","iam","config","aws","SESv2Client","GetConfigurationSetCommand","GetEmailIdentityCommand","config","aws","aws","IAMClient","iam","config","config","findHostedZone","createACMCertificate","createCloudFrontTracking","createMailManagerArchive","automation","installPulumiCli","pc","config","result","clack","pulumi","pc","IAMClient","GetIdentityVerificationAttributesCommand","ListIdentitiesCommand","SESClient","sns","lambda","iam","pc","result","findHostedZone","createDNSRecords","clack","pulumi","pc","SESv2Client","GetEmailIdentityCommand","pc","SESv2Client","clack","pc","pc","SESv2Client","clack","pulumi","pc","pc","promptEmailArchiving","result","findHostedZone","previewDNSChanges","createSelectedDNSRecords","promptDNSManagement","promptDNSConfirmation","clack","pulumi","pc","pc","clack","pulumi","pc","pc","SESv2Client","GetEmailIdentityCommand","identity","clack","pulumi","pc","pc","config","listSESDomains","findHostedZone","promptCustomConfig","result","createDNSRecords","clack","pulumi","pc","path","fileURLToPath","SESClient","GetEmailIdentityCommand","SESv2Client","sesv2","config","createRouter","DynamoDBClient","dynamodb","status","config","createRouter","fetchArchivedEmail","createRouter","cloudwatch","fetchDynamoDBMetrics","config","createRouter","log","createRouter","GetEmailIdentityCommand","SESv2Client","sesv2","config","createRouter","SESv2Client","assumeRole","createRouter","DynamoDBClient","QueryCommand","ScanCommand","unmarshall","dynamodb","status","CloudWatchClient","GetMetricDataCommand","DynamoDBClient","ScanCommand","unmarshall","cloudwatch","dynamodb","getEventPriority","PinpointSMSVoiceV2Client","status","config","createRouter","createRouter","config","createRouter","assumeRole","IAMClient","__dirname","path","fileURLToPath","config","pc","clack","pc","pc","spinner","clack","pulumi","pc","pc","clack","pulumi","pc","aws","pulumi","roleExists","IAMClient","GetRoleCommand","iam","tableExists","DynamoDBClient","DescribeTableCommand","dynamodb","config","PinpointSMSVoiceV2Client","DescribePhoneNumbersCommand","sqs","SNSClient","ListTopicsCommand","sns","topicArn","getLambdaCode","DescribeConfigurationSetsCommand","pc","pc","clack","pulumi","pc","FREE_TIER","estimateStorageSize","config","calculateEventTrackingCost","calculateDynamoDBCost","calculateTrackingCost","formatCost","config","formatCost","config","init","pc","clack","pc","PinpointSMSVoiceV2Client","DescribePhoneNumbersCommand","pc","exec","promisify","execAsync","clack","pulumi","pc","pc","clack","pulumi","pc","pc","PinpointSMSVoiceV2Client","clack","pc","pc","PinpointSMSVoiceV2Client","clack","pulumi","pc","pc","config","phoneTypeLabels","formatCost","PinpointSMSVoiceV2Client","clack","pc","isValidPhoneNumber","pc","PinpointSMSVoiceV2Client","status","phoneNumber","clack","pc","status","__filename","fileURLToPath","__dirname","dirname","join","pc","init"]}