@jadenrazo/cloudcost-mcp 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -24,7 +24,7 @@
24
24
 
25
25
  ---
26
26
 
27
- CloudCost MCP is an MCP server that lets AI agents parse Terraform codebases, query real-time pricing data, and generate multi-cloud cost comparison reports. It connects directly to public pricing APIs from AWS and Azure — no API keys or cloud credentials required. GCP pricing is bundled from public catalog data.
27
+ CloudCost MCP is a [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server — a standardized way to give AI assistants like Claude access to external tools — that lets AI agents parse Terraform codebases, query real-time pricing data, and generate multi-cloud cost comparison reports. It connects directly to public pricing APIs from AWS and Azure — no API keys or cloud credentials required. GCP pricing is bundled from public catalog data.
28
28
 
29
29
  ### What it does
30
30
 
@@ -54,6 +54,12 @@ Or install from npm:
54
54
  npm install -g @jadenrazo/cloudcost-mcp
55
55
  ```
56
56
 
57
+ Or run directly without installing:
58
+
59
+ ```bash
60
+ npx -y @jadenrazo/cloudcost-mcp
61
+ ```
62
+
57
63
  ### Claude Desktop
58
64
 
59
65
  Add to your Claude Desktop MCP configuration (`claude_desktop_config.json`):
@@ -63,7 +69,7 @@ Add to your Claude Desktop MCP configuration (`claude_desktop_config.json`):
63
69
  "mcpServers": {
64
70
  "cloudcost": {
65
71
  "command": "node",
66
- "args": ["/path/to/cloudcost-mcp/dist/index.js"]
72
+ "args": ["/path/to/CloudCostMCP/dist/index.js"]
67
73
  }
68
74
  }
69
75
  }
@@ -84,7 +90,13 @@ If installed globally via npm:
84
90
  ### Claude Code
85
91
 
86
92
  ```bash
87
- claude mcp add cloudcost -- node /path/to/cloudcost-mcp/dist/index.js
93
+ claude mcp add cloudcost -- node /path/to/CloudCostMCP/dist/index.js
94
+ ```
95
+
96
+ Or if installed globally via npm:
97
+
98
+ ```bash
99
+ claude mcp add cloudcost -- cloudcost-mcp
88
100
  ```
89
101
 
90
102
  ### As a standalone MCP server (stdio)
@@ -201,7 +213,48 @@ All pricing data is cached in a local SQLite database (`~/.cloudcost/cache.db`)
201
213
 
202
214
  ## Example
203
215
 
204
- Running `compare_providers` against a typical AWS Terraform config with 3 web servers (t3.xlarge), 2 app servers (m5.2xlarge), an RDS instance (db.r6g.xlarge), EBS volumes, S3, ALB, NAT Gateway, and an EKS cluster:
216
+ Given this Terraform config:
217
+
218
+ ```hcl
219
+ # infrastructure.tf
220
+ resource "aws_instance" "web" {
221
+ count = 3
222
+ ami = "ami-0c55b159cbfafe1f0"
223
+ instance_type = "t3.xlarge"
224
+ }
225
+
226
+ resource "aws_instance" "app" {
227
+ count = 2
228
+ ami = "ami-0c55b159cbfafe1f0"
229
+ instance_type = "m5.2xlarge"
230
+ }
231
+
232
+ resource "aws_db_instance" "primary" {
233
+ instance_class = "db.r6g.xlarge"
234
+ engine = "postgres"
235
+ allocated_storage = 200
236
+ }
237
+
238
+ resource "aws_ebs_volume" "data" {
239
+ count = 5
240
+ size = 500
241
+ type = "gp3"
242
+ }
243
+
244
+ resource "aws_s3_bucket" "assets" {}
245
+
246
+ resource "aws_lb" "main" {
247
+ load_balancer_type = "application"
248
+ }
249
+
250
+ resource "aws_nat_gateway" "main" {}
251
+
252
+ resource "aws_eks_cluster" "main" {
253
+ name = "prod"
254
+ }
255
+ ```
256
+
257
+ Running `compare_providers` against that config produces:
205
258
 
206
259
  ```
207
260
  | Category | AWS (USD/mo) | Azure (USD/mo) | GCP (USD/mo) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jadenrazo/cloudcost-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "MCP server for multi-cloud cost analysis of Terraform codebases",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -28,6 +28,7 @@
28
28
  },
29
29
  "files": [
30
30
  "dist",
31
+ "!dist/**/*.map",
31
32
  "data",
32
33
  "README.md",
33
34
  "LICENSE"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/data/loader.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type {\n ResourceEquivalent,\n RegionMapping,\n StorageMapping,\n InstanceSpec,\n} from \"../types/index.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// Resolve the project root by walking up from the current file until we find\n// package.json. This works both during development (src/data/loader.ts) and\n// after bundling (dist/chunk-*.js) regardless of directory depth.\nfunction findProjectRoot(startDir: string): string {\n let dir = startDir;\n while (true) {\n try {\n readFileSync(join(dir, \"package.json\"), \"utf-8\");\n return dir;\n } catch {\n const parent = dirname(dir);\n if (parent === dir) return startDir; // filesystem root, give up\n dir = parent;\n }\n }\n}\n\nconst DATA_DIR = join(findProjectRoot(__dirname), \"data\");\n\n// ---------------------------------------------------------------------------\n// Internal types for structured JSON shapes that don't directly map to\n// exported domain types (e.g. nested maps or objects with mixed fields).\n// ---------------------------------------------------------------------------\n\nexport interface InstanceMapData {\n aws_to_azure: Record<string, string>;\n aws_to_gcp: Record<string, string>;\n azure_to_aws: Record<string, string>;\n azure_to_gcp: Record<string, string>;\n gcp_to_aws: Record<string, string>;\n gcp_to_azure: Record<string, string>;\n}\n\nexport interface StorageMapData {\n block_storage: StorageMapping[];\n object_storage: Array<{\n category: string;\n aws: string;\n azure: string;\n gcp: string;\n }>;\n}\n\nexport interface GcpSqlRegionPricing {\n [tier: string]: number; // tier keys like \"db-custom-1-3840\", plus \"storage_per_gb\" and \"ha_multiplier\"\n}\n\nexport interface GcpStorageRegionPricing {\n STANDARD: number;\n NEARLINE: number;\n COLDLINE: number;\n ARCHIVE: number;\n}\n\nexport interface GcpDiskRegionPricing {\n \"pd-standard\": number;\n \"pd-ssd\": number;\n \"pd-balanced\": number;\n}\n\n// ---------------------------------------------------------------------------\n// Generic file loader – reads and parses a JSON file relative to DATA_DIR.\n// Throws with the file path in the message if anything goes wrong so callers\n// always know which file caused a problem.\n// ---------------------------------------------------------------------------\n\nfunction loadJsonFile<T>(relativePath: string): T {\n const fullPath = join(DATA_DIR, relativePath);\n try {\n return JSON.parse(readFileSync(fullPath, \"utf-8\")) as T;\n } catch (err) {\n throw new Error(\n `Failed to load data file \"${fullPath}\": ${err instanceof Error ? err.message : String(err)}`\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Lazy-loaded module-level singletons. Each is initialised exactly once on\n// first access and then cached for the lifetime of the process.\n// ---------------------------------------------------------------------------\n\nlet _resourceEquivalents: ResourceEquivalent[] | null = null;\nlet _instanceMap: InstanceMapData | null = null;\nlet _regionMappings: RegionMapping[] | null = null;\nlet _storageMap: StorageMapData | null = null;\nlet _awsInstances: InstanceSpec[] | null = null;\nlet _azureVmSizes: InstanceSpec[] | null = null;\nlet _gcpMachineTypes: InstanceSpec[] | null = null;\nlet _gcpComputePricing: Record<string, Record<string, number>> | null = null;\nlet _gcpSqlPricing: Record<string, GcpSqlRegionPricing> | null = null;\nlet _gcpStoragePricing: Record<string, GcpStorageRegionPricing> | null = null;\nlet _gcpDiskPricing: Record<string, GcpDiskRegionPricing> | null = null;\n\n// ---------------------------------------------------------------------------\n// Public accessor functions\n// ---------------------------------------------------------------------------\n\n/**\n * Returns all cross-provider resource equivalents (e.g. aws_instance <-> azurerm_linux_virtual_machine).\n */\nexport function getResourceEquivalents(): ResourceEquivalent[] {\n if (_resourceEquivalents === null) {\n _resourceEquivalents = loadJsonFile<ResourceEquivalent[]>(\n \"resource-equivalents.json\"\n );\n }\n return _resourceEquivalents;\n}\n\n/**\n * Returns the pre-computed bidirectional instance type mapping table\n * covering all six provider-pair directions.\n */\nexport function getInstanceMap(): InstanceMapData {\n if (_instanceMap === null) {\n _instanceMap = loadJsonFile<InstanceMapData>(\"instance-map.json\");\n }\n return _instanceMap;\n}\n\n/**\n * Returns the list of geographically equivalent regions across AWS, Azure, and GCP.\n */\nexport function getRegionMappings(): RegionMapping[] {\n if (_regionMappings === null) {\n _regionMappings = loadJsonFile<RegionMapping[]>(\"region-mappings.json\");\n }\n return _regionMappings;\n}\n\n/**\n * Returns the storage tier mapping data covering both block and object storage\n * across all three providers.\n */\nexport function getStorageMap(): StorageMapData {\n if (_storageMap === null) {\n _storageMap = loadJsonFile<StorageMapData>(\"storage-map.json\");\n }\n return _storageMap;\n}\n\n/**\n * Returns the catalogue of AWS EC2 and RDS instance specifications.\n */\nexport function getAwsInstances(): InstanceSpec[] {\n if (_awsInstances === null) {\n _awsInstances = loadJsonFile<InstanceSpec[]>(\n \"instance-types/aws-instances.json\"\n );\n }\n return _awsInstances;\n}\n\n/**\n * Returns the catalogue of Azure VM size specifications.\n */\nexport function getAzureVmSizes(): InstanceSpec[] {\n if (_azureVmSizes === null) {\n _azureVmSizes = loadJsonFile<InstanceSpec[]>(\n \"instance-types/azure-vm-sizes.json\"\n );\n }\n return _azureVmSizes;\n}\n\n/**\n * Returns the catalogue of GCP Compute Engine and Cloud SQL machine type specifications.\n */\nexport function getGcpMachineTypes(): InstanceSpec[] {\n if (_gcpMachineTypes === null) {\n _gcpMachineTypes = loadJsonFile<InstanceSpec[]>(\n \"instance-types/gcp-machine-types.json\"\n );\n }\n return _gcpMachineTypes;\n}\n\n/**\n * Returns bundled GCP Compute Engine on-demand hourly pricing keyed by\n * region then machine type.\n */\nexport function getGcpComputePricing(): Record<string, Record<string, number>> {\n if (_gcpComputePricing === null) {\n _gcpComputePricing = loadJsonFile<Record<string, Record<string, number>>>(\n \"gcp-pricing/compute-engine.json\"\n );\n }\n return _gcpComputePricing;\n}\n\n/**\n * Returns bundled GCP Cloud SQL hourly pricing keyed by region.\n * Each region entry maps tier names (and the special keys \"storage_per_gb\"\n * and \"ha_multiplier\") to numeric values.\n */\nexport function getGcpSqlPricing(): Record<string, GcpSqlRegionPricing> {\n if (_gcpSqlPricing === null) {\n _gcpSqlPricing = loadJsonFile<Record<string, GcpSqlRegionPricing>>(\n \"gcp-pricing/cloud-sql.json\"\n );\n }\n return _gcpSqlPricing;\n}\n\n/**\n * Returns bundled GCP Cloud Storage per-GB/month pricing keyed by region\n * then storage class (STANDARD, NEARLINE, COLDLINE, ARCHIVE).\n */\nexport function getGcpStoragePricing(): Record<string, GcpStorageRegionPricing> {\n if (_gcpStoragePricing === null) {\n _gcpStoragePricing = loadJsonFile<Record<string, GcpStorageRegionPricing>>(\n \"gcp-pricing/cloud-storage.json\"\n );\n }\n return _gcpStoragePricing;\n}\n\n/**\n * Returns bundled GCP Persistent Disk per-GB/month pricing keyed by region\n * then disk type (pd-standard, pd-ssd, pd-balanced).\n */\nexport function getGcpDiskPricing(): Record<string, GcpDiskRegionPricing> {\n if (_gcpDiskPricing === null) {\n _gcpDiskPricing = loadJsonFile<Record<string, GcpDiskRegionPricing>>(\n \"gcp-pricing/persistent-disk.json\"\n );\n }\n return _gcpDiskPricing;\n}\n\n// ---------------------------------------------------------------------------\n// Cache reset – only useful in tests that need a clean slate between runs.\n// Not exported to consumers; imported via the test helper path if needed.\n// ---------------------------------------------------------------------------\n\n/** @internal */\nexport function _resetLoaderCache(): void {\n _resourceEquivalents = null;\n _instanceMap = null;\n _regionMappings = null;\n _storageMap = null;\n _awsInstances = null;\n _azureVmSizes = null;\n _gcpMachineTypes = null;\n _gcpComputePricing = null;\n _gcpSqlPricing = null;\n _gcpStoragePricing = null;\n _gcpDiskPricing = null;\n}\n"],"mappings":";;;AAAA,SAAS,oBAAoB;AAC7B,SAAS,MAAM,eAAe;AAC9B,SAAS,qBAAqB;AAQ9B,IAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAKxD,SAAS,gBAAgB,UAA0B;AACjD,MAAI,MAAM;AACV,SAAO,MAAM;AACX,QAAI;AACF,mBAAa,KAAK,KAAK,cAAc,GAAG,OAAO;AAC/C,aAAO;AAAA,IACT,QAAQ;AACN,YAAM,SAAS,QAAQ,GAAG;AAC1B,UAAI,WAAW,IAAK,QAAO;AAC3B,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,IAAM,WAAW,KAAK,gBAAgB,SAAS,GAAG,MAAM;AAiDxD,SAAS,aAAgB,cAAyB;AAChD,QAAM,WAAW,KAAK,UAAU,YAAY;AAC5C,MAAI;AACF,WAAO,KAAK,MAAM,aAAa,UAAU,OAAO,CAAC;AAAA,EACnD,SAAS,KAAK;AACZ,UAAM,IAAI;AAAA,MACR,6BAA6B,QAAQ,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC7F;AAAA,EACF;AACF;AAOA,IAAI,uBAAoD;AACxD,IAAI,eAAuC;AAC3C,IAAI,kBAA0C;AAC9C,IAAI,cAAqC;AACzC,IAAI,gBAAuC;AAC3C,IAAI,gBAAuC;AAC3C,IAAI,mBAA0C;AAC9C,IAAI,qBAAoE;AACxE,IAAI,iBAA6D;AACjE,IAAI,qBAAqE;AACzE,IAAI,kBAA+D;AAS5D,SAAS,yBAA+C;AAC7D,MAAI,yBAAyB,MAAM;AACjC,2BAAuB;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,iBAAkC;AAChD,MAAI,iBAAiB,MAAM;AACzB,mBAAe,aAA8B,mBAAmB;AAAA,EAClE;AACA,SAAO;AACT;AAKO,SAAS,oBAAqC;AACnD,MAAI,oBAAoB,MAAM;AAC5B,sBAAkB,aAA8B,sBAAsB;AAAA,EACxE;AACA,SAAO;AACT;AAMO,SAAS,gBAAgC;AAC9C,MAAI,gBAAgB,MAAM;AACxB,kBAAc,aAA6B,kBAAkB;AAAA,EAC/D;AACA,SAAO;AACT;AAKO,SAAS,kBAAkC;AAChD,MAAI,kBAAkB,MAAM;AAC1B,oBAAgB;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAKO,SAAS,kBAAkC;AAChD,MAAI,kBAAkB,MAAM;AAC1B,oBAAgB;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAKO,SAAS,qBAAqC;AACnD,MAAI,qBAAqB,MAAM;AAC7B,uBAAmB;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,uBAA+D;AAC7E,MAAI,uBAAuB,MAAM;AAC/B,yBAAqB;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,mBAAwD;AACtE,MAAI,mBAAmB,MAAM;AAC3B,qBAAiB;AAAA,MACf;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,uBAAgE;AAC9E,MAAI,uBAAuB,MAAM;AAC/B,yBAAqB;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,oBAA0D;AACxE,MAAI,oBAAoB,MAAM;AAC5B,sBAAkB;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAQO,SAAS,oBAA0B;AACxC,yBAAuB;AACvB,iBAAe;AACf,oBAAkB;AAClB,gBAAc;AACd,kBAAgB;AAChB,kBAAgB;AAChB,qBAAmB;AACnB,uBAAqB;AACrB,mBAAiB;AACjB,uBAAqB;AACrB,oBAAkB;AACpB;","names":[]}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server.ts","../src/config.ts","../src/types/config.ts","../src/logger.ts","../src/pricing/cache.ts","../src/pricing/aws/aws-normalizer.ts","../src/pricing/aws/bulk-loader.ts","../src/pricing/azure/azure-normalizer.ts","../src/pricing/azure/retail-client.ts","../src/pricing/gcp/gcp-normalizer.ts","../src/pricing/gcp/bundled-loader.ts","../src/pricing/pricing-engine.ts","../src/tools/analyze-terraform.ts","../src/parsers/hcl-parser.ts","../src/parsers/variable-resolver.ts","../src/parsers/provider-detector.ts","../src/parsers/resource-extractor.ts","../src/parsers/index.ts","../src/tools/estimate-cost.ts","../src/mapping/region-mapper.ts","../src/mapping/instance-mapper.ts","../src/mapping/storage-mapper.ts","../src/calculator/compute.ts","../src/calculator/database.ts","../src/calculator/storage.ts","../src/calculator/network.ts","../src/calculator/kubernetes.ts","../src/calculator/cost-engine.ts","../src/tools/compare-providers.ts","../src/calculator/reserved.ts","../src/calculator/optimizer.ts","../src/reporting/markdown-report.ts","../src/reporting/json-report.ts","../src/reporting/csv-report.ts","../src/tools/get-equivalents.ts","../src/mapping/resource-mapper.ts","../src/tools/get-pricing.ts","../src/tools/optimize-cost.ts","../src/tools/index.ts","../src/index.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { loadConfig } from \"./config.js\";\nimport { setLogLevel, logger } from \"./logger.js\";\nimport { registerTools } from \"./tools/index.js\";\n\nexport async function startServer(): Promise<void> {\n const config = loadConfig();\n setLogLevel(config.logging.level);\n\n const server = new McpServer({\n name: \"cloudcost-mcp\",\n version: \"0.1.0\",\n });\n\n registerTools(server, config);\n\n const transport = new StdioServerTransport();\n logger.info(\"Starting CloudCost MCP server\");\n await server.connect(transport);\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { type CloudCostConfig, DEFAULT_CONFIG } from \"./types/config.js\";\n\nfunction getConfigDir(): string {\n return join(homedir(), \".cloudcost\");\n}\n\nfunction loadFileConfig(): Partial<CloudCostConfig> {\n const configPath = join(getConfigDir(), \"config.json\");\n if (!existsSync(configPath)) return {};\n try {\n return JSON.parse(readFileSync(configPath, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nfunction loadEnvConfig(): Partial<CloudCostConfig> {\n const config: Partial<CloudCostConfig> = {};\n const env = process.env;\n\n if (env.CLOUDCOST_CACHE_TTL || env.CLOUDCOST_CACHE_PATH) {\n config.cache = {\n ttl_seconds: env.CLOUDCOST_CACHE_TTL\n ? parseInt(env.CLOUDCOST_CACHE_TTL, 10)\n : DEFAULT_CONFIG.cache.ttl_seconds,\n db_path: env.CLOUDCOST_CACHE_PATH ?? \"\",\n };\n }\n\n if (env.CLOUDCOST_LOG_LEVEL) {\n config.logging = {\n level: env.CLOUDCOST_LOG_LEVEL as CloudCostConfig[\"logging\"][\"level\"],\n };\n }\n\n if (env.CLOUDCOST_MONTHLY_HOURS) {\n config.pricing = {\n ...DEFAULT_CONFIG.pricing,\n monthly_hours: parseInt(env.CLOUDCOST_MONTHLY_HOURS, 10),\n };\n }\n\n return config;\n}\n\nexport function loadConfig(): CloudCostConfig {\n const fileConfig = loadFileConfig();\n const envConfig = loadEnvConfig();\n\n const defaultDbPath = join(getConfigDir(), \"cache.db\");\n\n return {\n cache: {\n ...DEFAULT_CONFIG.cache,\n db_path: defaultDbPath,\n ...fileConfig.cache,\n ...envConfig.cache,\n },\n pricing: {\n ...DEFAULT_CONFIG.pricing,\n ...fileConfig.pricing,\n ...envConfig.pricing,\n },\n logging: {\n ...DEFAULT_CONFIG.logging,\n ...fileConfig.logging,\n ...envConfig.logging,\n },\n };\n}\n","export interface CloudCostConfig {\n cache: CacheConfig;\n pricing: PricingConfig;\n logging: LogConfig;\n}\n\nexport interface CacheConfig {\n ttl_seconds: number;\n db_path: string;\n}\n\nexport interface PricingConfig {\n monthly_hours: number;\n default_currency: string;\n aws_pricing_region: string;\n}\n\nexport interface LogConfig {\n level: \"debug\" | \"info\" | \"warn\" | \"error\";\n}\n\nexport const DEFAULT_CONFIG: CloudCostConfig = {\n cache: {\n ttl_seconds: 86400,\n db_path: \"\",\n },\n pricing: {\n monthly_hours: 730,\n default_currency: \"USD\",\n aws_pricing_region: \"us-east-1\",\n },\n logging: {\n level: \"info\",\n },\n};\n","type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LEVEL_ORDER: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nlet currentLevel: LogLevel = \"info\";\n\nexport function setLogLevel(level: LogLevel): void {\n currentLevel = level;\n}\n\nfunction shouldLog(level: LogLevel): boolean {\n return LEVEL_ORDER[level] >= LEVEL_ORDER[currentLevel];\n}\n\nfunction log(level: LogLevel, message: string, data?: unknown): void {\n if (!shouldLog(level)) return;\n const timestamp = new Date().toISOString();\n const entry = data\n ? `[${timestamp}] ${level.toUpperCase()}: ${message} ${JSON.stringify(data)}`\n : `[${timestamp}] ${level.toUpperCase()}: ${message}`;\n // MCP uses stdout for JSON-RPC, so all logs go to stderr\n process.stderr.write(entry + \"\\n\");\n}\n\nexport const logger = {\n debug: (msg: string, data?: unknown) => log(\"debug\", msg, data),\n info: (msg: string, data?: unknown) => log(\"info\", msg, data),\n warn: (msg: string, data?: unknown) => log(\"warn\", msg, data),\n error: (msg: string, data?: unknown) => log(\"error\", msg, data),\n};\n","import Database from \"better-sqlite3\";\nimport { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { logger } from \"../logger.js\";\nimport type { CacheEntry, CacheStats } from \"./types.js\";\n\nconst SCHEMA = `\n CREATE TABLE IF NOT EXISTS pricing_cache (\n key TEXT PRIMARY KEY,\n data TEXT NOT NULL,\n provider TEXT NOT NULL,\n service TEXT NOT NULL,\n region TEXT NOT NULL,\n created_at TEXT NOT NULL,\n expires_at TEXT NOT NULL\n );\n CREATE INDEX IF NOT EXISTS idx_pricing_cache_provider ON pricing_cache (provider);\n CREATE INDEX IF NOT EXISTS idx_pricing_cache_expires_at ON pricing_cache (expires_at);\n`;\n\nexport class PricingCache {\n private db: Database.Database;\n\n constructor(dbPath: string) {\n mkdirSync(dirname(dbPath), { recursive: true });\n\n this.db = new Database(dbPath);\n\n // WAL mode allows concurrent readers alongside a single writer, which is\n // the dominant access pattern for a pricing cache.\n this.db.pragma(\"journal_mode = WAL\");\n this.db.pragma(\"foreign_keys = ON\");\n\n this.db.exec(SCHEMA);\n\n logger.debug(\"PricingCache initialised\", { dbPath });\n }\n\n /**\n * Retrieve a cached value by key. Returns null when the entry does not exist\n * or has already expired; expired rows are deleted as a side-effect so the\n * table self-trims on read.\n */\n get<T>(key: string): T | null {\n const row = this.db\n .prepare<[string], CacheEntry>(\n \"SELECT * FROM pricing_cache WHERE key = ?\"\n )\n .get(key);\n\n if (!row) return null;\n\n const now = new Date().toISOString();\n if (row.expires_at <= now) {\n this.db\n .prepare(\"DELETE FROM pricing_cache WHERE key = ?\")\n .run(key);\n logger.debug(\"Cache miss (expired)\", { key });\n return null;\n }\n\n logger.debug(\"Cache hit\", { key });\n return JSON.parse(row.data) as T;\n }\n\n /**\n * Store a value in the cache.\n *\n * The composite key convention for pricing lookups is:\n * `{provider}/{service}/{region}/{resource_type}`\n *\n * Callers are responsible for constructing the key before calling this\n * method; the method itself treats the key as an opaque string so it can\n * be reused for other cache domains in the future.\n */\n set<T>(\n key: string,\n data: T,\n provider: string,\n service: string,\n region: string,\n ttlSeconds: number\n ): void {\n const now = new Date();\n const expiresAt = new Date(now.getTime() + ttlSeconds * 1000);\n\n this.db\n .prepare(\n `INSERT INTO pricing_cache (key, data, provider, service, region, created_at, expires_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (key) DO UPDATE SET\n data = excluded.data,\n provider = excluded.provider,\n service = excluded.service,\n region = excluded.region,\n created_at = excluded.created_at,\n expires_at = excluded.expires_at`\n )\n .run(\n key,\n JSON.stringify(data),\n provider,\n service,\n region,\n now.toISOString(),\n expiresAt.toISOString()\n );\n\n logger.debug(\"Cache set\", { key, ttlSeconds });\n }\n\n /** Remove a single cache entry. */\n invalidate(key: string): void {\n const result = this.db\n .prepare(\"DELETE FROM pricing_cache WHERE key = ?\")\n .run(key);\n logger.debug(\"Cache invalidated\", { key, removed: result.changes });\n }\n\n /** Remove every cache entry belonging to a provider. */\n invalidateByProvider(provider: string): void {\n const result = this.db\n .prepare(\"DELETE FROM pricing_cache WHERE provider = ?\")\n .run(provider);\n logger.debug(\"Cache invalidated by provider\", {\n provider,\n removed: result.changes,\n });\n }\n\n /**\n * Delete all entries whose expiry timestamp is in the past.\n * Returns the number of rows removed.\n */\n cleanup(): number {\n const now = new Date().toISOString();\n const result = this.db\n .prepare(\"DELETE FROM pricing_cache WHERE expires_at <= ?\")\n .run(now);\n const removed = result.changes;\n logger.debug(\"Cache cleanup complete\", { removed });\n return removed;\n }\n\n /** Return aggregate statistics about the current cache state. */\n getStats(): CacheStats {\n const now = new Date().toISOString();\n\n const totals = this.db\n .prepare<[], { total_entries: number; size_bytes: number }>(\n `SELECT\n COUNT(*) AS total_entries,\n COALESCE(SUM(LENGTH(data)), 0) AS size_bytes\n FROM pricing_cache`\n )\n .get()!;\n\n const expired = this.db\n .prepare<[string], { expired_entries: number }>(\n \"SELECT COUNT(*) AS expired_entries FROM pricing_cache WHERE expires_at <= ?\"\n )\n .get(now)!;\n\n return {\n total_entries: totals.total_entries,\n expired_entries: expired.expired_entries,\n size_bytes: totals.size_bytes,\n };\n }\n\n /** Close the underlying database connection. */\n close(): void {\n this.db.close();\n logger.debug(\"PricingCache closed\");\n }\n}\n","import type { NormalizedPrice } from \"../../types/pricing.js\";\n\n/**\n * Convert a raw AWS bulk pricing product + price term into a NormalizedPrice.\n *\n * AWS bulk JSON has the shape:\n * products[sku].attributes – metadata about the SKU\n * terms.OnDemand[sku][offerTermCode].priceDimensions[rateCode] – price info\n */\n\nfunction extractUsdPrice(priceDimensions: Record<string, any>): number {\n for (const dim of Object.values(priceDimensions)) {\n const usd = dim?.pricePerUnit?.USD;\n if (usd !== undefined) {\n const val = parseFloat(usd);\n if (!isNaN(val)) return val;\n }\n }\n return 0;\n}\n\nfunction extractUnit(priceDimensions: Record<string, any>): string {\n for (const dim of Object.values(priceDimensions)) {\n if (dim?.unit) return String(dim.unit);\n }\n return \"Hrs\";\n}\n\nexport function normalizeAwsCompute(\n rawProduct: any,\n rawPrice: any,\n region: string\n): NormalizedPrice {\n const attrs = rawProduct?.attributes ?? {};\n const terms = rawPrice?.terms?.OnDemand ?? {};\n let price = 0;\n let unit = \"Hrs\";\n\n for (const term of Object.values(terms)) {\n const dims = (term as any)?.priceDimensions ?? {};\n price = extractUsdPrice(dims);\n unit = extractUnit(dims);\n break; // take the first on-demand term\n }\n\n return {\n provider: \"aws\",\n service: \"ec2\",\n resource_type: attrs.instanceType ?? \"unknown\",\n region,\n unit,\n price_per_unit: price,\n currency: \"USD\",\n description: attrs.instanceType\n ? `AWS EC2 ${attrs.instanceType} (${attrs.operatingSystem ?? \"Linux\"})`\n : undefined,\n attributes: {\n instance_type: attrs.instanceType ?? \"\",\n vcpu: attrs.vcpu ?? \"\",\n memory: attrs.memory ?? \"\",\n operating_system: attrs.operatingSystem ?? \"Linux\",\n tenancy: attrs.tenancy ?? \"Shared\",\n },\n effective_date: new Date().toISOString(),\n };\n}\n\nexport function normalizeAwsDatabase(\n rawProduct: any,\n rawPrice: any,\n region: string\n): NormalizedPrice {\n const attrs = rawProduct?.attributes ?? {};\n const terms = rawPrice?.terms?.OnDemand ?? {};\n let price = 0;\n let unit = \"Hrs\";\n\n for (const term of Object.values(terms)) {\n const dims = (term as any)?.priceDimensions ?? {};\n price = extractUsdPrice(dims);\n unit = extractUnit(dims);\n break;\n }\n\n return {\n provider: \"aws\",\n service: \"rds\",\n resource_type: attrs.instanceType ?? \"unknown\",\n region,\n unit,\n price_per_unit: price,\n currency: \"USD\",\n description: attrs.instanceType\n ? `AWS RDS ${attrs.instanceType} (${attrs.databaseEngine ?? \"MySQL\"})`\n : undefined,\n attributes: {\n instance_type: attrs.instanceType ?? \"\",\n database_engine: attrs.databaseEngine ?? \"\",\n deployment_option: attrs.deploymentOption ?? \"Single-AZ\",\n vcpu: attrs.vcpu ?? \"\",\n memory: attrs.memory ?? \"\",\n },\n effective_date: new Date().toISOString(),\n };\n}\n\nexport function normalizeAwsStorage(\n rawProduct: any,\n rawPrice: any,\n region: string\n): NormalizedPrice {\n const attrs = rawProduct?.attributes ?? {};\n const terms = rawPrice?.terms?.OnDemand ?? {};\n let price = 0;\n let unit = \"GB-Mo\";\n\n for (const term of Object.values(terms)) {\n const dims = (term as any)?.priceDimensions ?? {};\n price = extractUsdPrice(dims);\n unit = extractUnit(dims);\n break;\n }\n\n const volumeType = attrs.volumeApiName ?? attrs.volumeType ?? \"gp3\";\n\n return {\n provider: \"aws\",\n service: \"ebs\",\n resource_type: volumeType,\n region,\n unit,\n price_per_unit: price,\n currency: \"USD\",\n description: `AWS EBS ${volumeType} volume`,\n attributes: {\n volume_type: volumeType,\n max_iops: attrs.maxIopsvolume ?? \"\",\n max_throughput: attrs.maxThroughputvolume ?? \"\",\n },\n effective_date: new Date().toISOString(),\n };\n}\n","import type { NormalizedPrice } from \"../../types/pricing.js\";\nimport type { PricingCache } from \"../cache.js\";\nimport { logger } from \"../../logger.js\";\nimport {\n normalizeAwsCompute,\n normalizeAwsDatabase,\n normalizeAwsStorage,\n} from \"./aws-normalizer.js\";\n\n// ---------------------------------------------------------------------------\n// CSV parsing helper\n// ---------------------------------------------------------------------------\n\n/**\n * Parse a single CSV line into an array of fields. Handles:\n * - Fields wrapped in double-quotes\n * - Embedded commas inside quoted fields\n * - Escaped double-quotes represented as two consecutive double-quotes (\"\")\n */\nfunction parseCsvLine(line: string): string[] {\n const fields: string[] = [];\n let i = 0;\n const len = line.length;\n\n while (i <= len) {\n if (i === len) {\n // Trailing empty field after a terminal comma\n if (fields.length > 0 && line[len - 1] === \",\") {\n fields.push(\"\");\n }\n break;\n }\n\n if (line[i] === '\"') {\n // Quoted field\n i++; // skip opening quote\n let field = \"\";\n while (i < len) {\n if (line[i] === '\"') {\n if (i + 1 < len && line[i + 1] === '\"') {\n // Escaped double-quote\n field += '\"';\n i += 2;\n } else {\n // Closing quote\n i++;\n break;\n }\n } else {\n field += line[i];\n i++;\n }\n }\n fields.push(field);\n // Skip the comma separator (or end of string)\n if (i < len && line[i] === \",\") i++;\n } else {\n // Unquoted field — read until next comma or end\n const start = i;\n while (i < len && line[i] !== \",\") i++;\n fields.push(line.slice(start, i));\n if (i < len) i++; // skip comma\n }\n }\n\n return fields;\n}\n\n// ---------------------------------------------------------------------------\n// Fallback pricing data (approximate us-east-1 on-demand prices, 2024)\n// Used when the live AWS Bulk Pricing API is unreachable.\n// ---------------------------------------------------------------------------\n\nconst EC2_BASE_PRICES: Record<string, number> = {\n \"t2.micro\": 0.0116,\n \"t2.small\": 0.023,\n \"t2.medium\": 0.0464,\n \"t2.large\": 0.0928,\n \"t3.micro\": 0.0104,\n \"t3.small\": 0.0208,\n \"t3.medium\": 0.0416,\n \"t3.large\": 0.0832,\n \"t3.xlarge\": 0.1664,\n \"t3.2xlarge\": 0.3328,\n \"t3a.micro\": 0.0094,\n \"t3a.small\": 0.0188,\n \"t3a.medium\": 0.0376,\n \"t3a.large\": 0.0752,\n \"t3a.xlarge\": 0.1504,\n \"t4g.micro\": 0.0084,\n \"t4g.small\": 0.0168,\n \"t4g.medium\": 0.0336,\n \"t4g.large\": 0.0672,\n \"t4g.xlarge\": 0.1344,\n \"m5.large\": 0.096,\n \"m5.xlarge\": 0.192,\n \"m5.2xlarge\": 0.384,\n \"m5.4xlarge\": 0.768,\n \"m5a.large\": 0.086,\n \"m5a.xlarge\": 0.172,\n \"m5a.2xlarge\": 0.344,\n \"m5a.4xlarge\": 0.688,\n \"m6i.large\": 0.096,\n \"m6i.xlarge\": 0.192,\n \"m6i.2xlarge\": 0.384,\n \"m6i.4xlarge\": 0.768,\n \"m6i.8xlarge\": 1.536,\n \"m6g.large\": 0.077,\n \"m6g.xlarge\": 0.154,\n \"m6g.2xlarge\": 0.308,\n \"m6g.4xlarge\": 0.616,\n \"m7i.large\": 0.1008,\n \"m7i.xlarge\": 0.2016,\n \"m7i.2xlarge\": 0.4032,\n \"m7g.large\": 0.0816,\n \"m7g.xlarge\": 0.1632,\n \"m7g.2xlarge\": 0.3264,\n \"m7g.4xlarge\": 0.6528,\n \"c5.large\": 0.085,\n \"c5.xlarge\": 0.170,\n \"c5.2xlarge\": 0.340,\n \"c5a.large\": 0.077,\n \"c5a.xlarge\": 0.154,\n \"c5a.2xlarge\": 0.308,\n \"c6i.large\": 0.085,\n \"c6i.xlarge\": 0.170,\n \"c6i.2xlarge\": 0.340,\n \"c6g.large\": 0.068,\n \"c6g.xlarge\": 0.136,\n \"c6g.2xlarge\": 0.272,\n \"c6g.4xlarge\": 0.544,\n \"c7i.large\": 0.089,\n \"c7i.xlarge\": 0.178,\n \"c7i.2xlarge\": 0.357,\n \"c7g.large\": 0.072,\n \"c7g.xlarge\": 0.145,\n \"c7g.2xlarge\": 0.290,\n \"c7g.4xlarge\": 0.580,\n \"r5.large\": 0.126,\n \"r5.xlarge\": 0.252,\n \"r5.2xlarge\": 0.504,\n \"r5a.large\": 0.113,\n \"r5a.xlarge\": 0.226,\n \"r5a.2xlarge\": 0.452,\n \"r6i.large\": 0.126,\n \"r6i.xlarge\": 0.252,\n \"r6i.2xlarge\": 0.504,\n \"r6g.large\": 0.101,\n \"r6g.xlarge\": 0.202,\n \"r6g.2xlarge\": 0.403,\n \"r6g.4xlarge\": 0.806,\n \"r7i.large\": 0.133,\n \"r7i.xlarge\": 0.266,\n \"r7i.2xlarge\": 0.532,\n \"r7g.large\": 0.107,\n \"r7g.xlarge\": 0.214,\n \"r7g.2xlarge\": 0.428,\n \"r7g.4xlarge\": 0.856,\n};\n\nconst RDS_BASE_PRICES: Record<string, number> = {\n \"db.t3.micro\": 0.017,\n \"db.t3.small\": 0.034,\n \"db.t3.medium\": 0.068,\n \"db.t3.large\": 0.136,\n \"db.t4g.micro\": 0.016,\n \"db.t4g.small\": 0.032,\n \"db.t4g.medium\": 0.065,\n \"db.t4g.large\": 0.129,\n \"db.t4g.xlarge\": 0.258,\n \"db.m5.large\": 0.171,\n \"db.m5.xlarge\": 0.342,\n \"db.m6g.large\": 0.154,\n \"db.m6g.xlarge\": 0.308,\n \"db.m6g.2xlarge\": 0.616,\n \"db.m6i.large\": 0.171,\n \"db.m6i.xlarge\": 0.342,\n \"db.m6i.2xlarge\": 0.684,\n \"db.m7g.large\": 0.168,\n \"db.m7g.xlarge\": 0.336,\n \"db.m7g.2xlarge\": 0.672,\n \"db.r5.large\": 0.250,\n \"db.r5.xlarge\": 0.500,\n \"db.r5.2xlarge\": 1.000,\n \"db.r6g.large\": 0.218,\n \"db.r6g.xlarge\": 0.437,\n \"db.r6g.2xlarge\": 0.874,\n \"db.r6i.large\": 0.250,\n \"db.r6i.xlarge\": 0.500,\n \"db.r6i.2xlarge\": 1.000,\n};\n\nconst EBS_BASE_PRICES: Record<string, number> = {\n \"gp3\": 0.08,\n \"gp2\": 0.10,\n \"io2\": 0.125,\n \"io1\": 0.125,\n \"st1\": 0.045,\n \"sc1\": 0.015,\n};\n\n// ALB pricing per hour (fixed component)\nconst ALB_HOURLY = 0.0225;\nconst ALB_LCU_HOURLY = 0.008;\n\n// NAT Gateway pricing\nconst NAT_HOURLY = 0.045;\nconst NAT_PER_GB = 0.045;\n\n// EKS control plane\nconst EKS_HOURLY = 0.10;\n\n// ---------------------------------------------------------------------------\n// Regional price multipliers relative to us-east-1.\n// Keys are normalised to lower-case AWS region identifiers.\n// ---------------------------------------------------------------------------\n\nconst REGION_MULTIPLIERS: Record<string, number> = {\n \"us-east-1\": 1.0,\n \"us-east-2\": 1.0,\n \"us-west-1\": 1.08,\n \"us-west-2\": 1.0,\n \"eu-west-1\": 1.10,\n \"eu-west-2\": 1.12,\n \"eu-central-1\": 1.12,\n \"ap-southeast-1\": 1.15,\n \"ap-southeast-2\": 1.15,\n \"ap-northeast-1\": 1.12,\n \"ap-northeast-2\": 1.10,\n \"ap-south-1\": 1.08,\n \"sa-east-1\": 1.20,\n \"ca-central-1\": 1.08,\n \"eu-north-1\": 1.10,\n \"eu-south-1\": 1.12,\n \"me-south-1\": 1.15,\n \"af-south-1\": 1.22,\n};\n\nfunction regionMultiplier(region: string): number {\n return REGION_MULTIPLIERS[region.toLowerCase()] ?? 1.0;\n}\n\nconst CACHE_TTL = 86400; // 24 hours in seconds\n\n// AWS Bulk Pricing API base URL.\n// Service codes used: AmazonEC2, AmazonRDS, AmazonEBS\nconst BULK_PRICING_BASE =\n \"https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws\";\n\nexport class AwsBulkLoader {\n private cache: PricingCache;\n\n /**\n * Deduplicates concurrent streaming CSV fetches for the same region.\n * Keyed by region; value is the in-flight Promise<boolean>.\n */\n private ec2CsvFetchInProgress: Map<string, Promise<boolean>> = new Map();\n\n constructor(cache: PricingCache) {\n this.cache = cache;\n }\n\n // -------------------------------------------------------------------------\n // Public API\n // -------------------------------------------------------------------------\n\n async getComputePrice(\n instanceType: string,\n region: string,\n os: string = \"Linux\"\n ): Promise<NormalizedPrice | null> {\n const cacheKey = this.buildCacheKey(\"ec2\", region, instanceType, os);\n\n // Step 1: cache hit\n const cached = this.cache.get<NormalizedPrice>(cacheKey);\n if (cached) return cached;\n\n // Step 2: stream the CSV pricing file for this region (fast, ~267 MB, line-by-line)\n try {\n const csvOk = await this.fetchAndCacheEc2CsvPrices(region);\n if (csvOk) {\n const afterCsv = this.cache.get<NormalizedPrice>(cacheKey);\n if (afterCsv) return afterCsv;\n }\n } catch (err) {\n logger.debug(\"AWS EC2 CSV streaming failed\", {\n region,\n instanceType,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n\n // Step 3: fall back to JSON bulk API (kept for non-EC2 service compatibility)\n try {\n const bulk = await this.fetchBulkPricing(\"AmazonEC2\", region);\n if (bulk) {\n const result = this.extractEc2Price(bulk, instanceType, region, os);\n if (result) {\n this.cache.set(cacheKey, result, \"aws\", \"ec2\", region, CACHE_TTL);\n return result;\n }\n }\n } catch (err) {\n logger.debug(\"AWS bulk EC2 JSON fetch failed, using fallback\", {\n region,\n instanceType,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n\n // Step 4: hardcoded tables + size interpolation\n return this.fallbackComputePrice(instanceType, region, os, cacheKey);\n }\n\n async getDatabasePrice(\n instanceClass: string,\n region: string,\n engine: string = \"MySQL\"\n ): Promise<NormalizedPrice | null> {\n const cacheKey = this.buildCacheKey(\"rds\", region, instanceClass, engine);\n const cached = this.cache.get<NormalizedPrice>(cacheKey);\n if (cached) return cached;\n\n try {\n const bulk = await this.fetchBulkPricing(\"AmazonRDS\", region);\n if (bulk) {\n const result = this.extractRdsPrice(bulk, instanceClass, region, engine);\n if (result) {\n this.cache.set(cacheKey, result, \"aws\", \"rds\", region, CACHE_TTL);\n return result;\n }\n }\n } catch (err) {\n logger.debug(\"AWS bulk RDS fetch failed, using fallback\", {\n region,\n instanceClass,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n\n return this.fallbackDatabasePrice(instanceClass, region, engine, cacheKey);\n }\n\n async getStoragePrice(\n volumeType: string,\n region: string\n ): Promise<NormalizedPrice | null> {\n const cacheKey = this.buildCacheKey(\"ebs\", region, volumeType);\n const cached = this.cache.get<NormalizedPrice>(cacheKey);\n if (cached) return cached;\n\n try {\n const bulk = await this.fetchBulkPricing(\"AmazonEC2\", region);\n if (bulk) {\n const result = this.extractEbsPrice(bulk, volumeType, region);\n if (result) {\n this.cache.set(cacheKey, result, \"aws\", \"ebs\", region, CACHE_TTL);\n return result;\n }\n }\n } catch (err) {\n logger.debug(\"AWS bulk EBS fetch failed, using fallback\", {\n region,\n volumeType,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n\n return this.fallbackStoragePrice(volumeType, region, cacheKey);\n }\n\n async getLoadBalancerPrice(region: string): Promise<NormalizedPrice | null> {\n const multiplier = regionMultiplier(region);\n return {\n provider: \"aws\",\n service: \"elb\",\n resource_type: \"alb\",\n region,\n unit: \"Hrs\",\n price_per_unit: ALB_HOURLY * multiplier,\n currency: \"USD\",\n description: \"AWS Application Load Balancer (hourly fixed charge)\",\n attributes: {\n lcu_hourly_price: String(ALB_LCU_HOURLY * multiplier),\n pricing_model: \"fixed_plus_lcu\",\n },\n effective_date: new Date().toISOString(),\n };\n }\n\n async getNatGatewayPrice(region: string): Promise<NormalizedPrice | null> {\n const multiplier = regionMultiplier(region);\n return {\n provider: \"aws\",\n service: \"vpc\",\n resource_type: \"nat-gateway\",\n region,\n unit: \"Hrs\",\n price_per_unit: NAT_HOURLY * multiplier,\n currency: \"USD\",\n description: \"AWS NAT Gateway (hourly charge + data processing)\",\n attributes: {\n per_gb_price: String(NAT_PER_GB * multiplier),\n },\n effective_date: new Date().toISOString(),\n };\n }\n\n async getKubernetesPrice(region: string): Promise<NormalizedPrice | null> {\n const multiplier = regionMultiplier(region);\n return {\n provider: \"aws\",\n service: \"eks\",\n resource_type: \"cluster\",\n region,\n unit: \"Hrs\",\n price_per_unit: EKS_HOURLY * multiplier,\n currency: \"USD\",\n description: \"AWS EKS control plane (per cluster/hour)\",\n attributes: {},\n effective_date: new Date().toISOString(),\n };\n }\n\n // -------------------------------------------------------------------------\n // Internal helpers – EC2 CSV streaming\n // -------------------------------------------------------------------------\n\n /**\n * Fetch the per-region EC2 pricing CSV from the AWS Bulk Pricing endpoint,\n * stream it line-by-line, parse every \"Compute Instance / OnDemand / Shared\"\n * row for ALL operating systems, and write each extracted price into the\n * SQLite cache.\n *\n * The CSV URL pattern is:\n * https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/{region}/index.csv\n *\n * The first ~5 rows of the file are metadata (FormatVersion, Disclaimer,\n * Publication Date, etc.). The actual header row is the first row whose\n * first field is \"SKU\".\n *\n * Returns true when at least one price was extracted and cached.\n */\n private fetchAndCacheEc2CsvPrices(region: string): Promise<boolean> {\n // Deduplicate concurrent requests for the same region\n const inflight = this.ec2CsvFetchInProgress.get(region);\n if (inflight) return inflight;\n\n const promise = this._doFetchAndCacheEc2CsvPrices(region).finally(() => {\n this.ec2CsvFetchInProgress.delete(region);\n });\n\n this.ec2CsvFetchInProgress.set(region, promise);\n return promise;\n }\n\n private async _doFetchAndCacheEc2CsvPrices(region: string): Promise<boolean> {\n const url = `${BULK_PRICING_BASE}/AmazonEC2/current/${region}/index.csv`;\n logger.debug(\"Streaming AWS EC2 CSV pricing\", { url, region });\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 120_000);\n\n try {\n const res = await fetch(url, { signal: controller.signal });\n if (!res.ok) {\n logger.debug(\"AWS EC2 CSV fetch returned non-OK status\", {\n region,\n status: res.status,\n });\n return false;\n }\n\n if (!res.body) {\n logger.debug(\"AWS EC2 CSV response has no body\", { region });\n return false;\n }\n\n // Stream the response body through a TextDecoder so we work with strings\n const reader = res.body\n .pipeThrough(new TextDecoderStream())\n .getReader();\n\n // Column indices discovered from the header row\n let colInstanceType = -1;\n let colOS = -1;\n let colTenancy = -1;\n let colTermType = -1;\n let colCapacityStatus = -1;\n let colProductFamily = -1;\n let colPrice = -1;\n let colUnit = -1;\n\n let headerFound = false;\n let leftover = \"\";\n let cachedCount = 0;\n const effectiveDate = new Date().toISOString();\n\n // Process the stream chunk-by-chunk, splitting on newlines\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n\n const chunk = leftover + value;\n const lines = chunk.split(\"\\n\");\n // The last element may be an incomplete line – carry it over\n leftover = lines.pop() ?? \"\";\n\n for (const rawLine of lines) {\n const line = rawLine.trimEnd(); // remove \\r if CRLF\n if (!line) continue;\n\n if (!headerFound) {\n // Metadata rows look like: \"FormatVersion\",\"1.0\"\n // The real header starts with \"SKU\"\n if (line.startsWith('\"SKU\"') || line.startsWith(\"SKU\")) {\n const headers = parseCsvLine(line);\n for (let h = 0; h < headers.length; h++) {\n const name = headers[h]!.trim();\n if (name === \"Instance Type\") colInstanceType = h;\n else if (name === \"Operating System\") colOS = h;\n else if (name === \"Tenancy\") colTenancy = h;\n else if (name === \"TermType\") colTermType = h;\n else if (name === \"Capacity Status\") colCapacityStatus = h;\n else if (name === \"Product Family\") colProductFamily = h;\n else if (name === \"PricePerUnit\" || name === \"Price Per Unit\") colPrice = h;\n else if (name === \"Unit\") colUnit = h;\n }\n\n // Only proceed if we found the minimum required columns\n if (\n colInstanceType === -1 ||\n colOS === -1 ||\n colPrice === -1\n ) {\n logger.debug(\"AWS EC2 CSV header missing required columns\", {\n region,\n colInstanceType,\n colOS,\n colPrice,\n });\n return false;\n }\n\n headerFound = true;\n }\n continue; // metadata row – skip\n }\n\n // Quick pre-filter before expensive CSV parsing\n if (!line.includes(\"OnDemand\") || !line.includes(\"Compute Instance\")) {\n continue;\n }\n\n const fields = parseCsvLine(line);\n\n // Apply filters for the rows we care about\n if (colProductFamily !== -1) {\n const pf = fields[colProductFamily] ?? \"\";\n if (pf !== \"Compute Instance\") continue;\n }\n if (colTenancy !== -1) {\n const tenancy = fields[colTenancy] ?? \"\";\n if (tenancy !== \"Shared\") continue;\n }\n if (colTermType !== -1) {\n const termType = fields[colTermType] ?? \"\";\n if (termType !== \"OnDemand\") continue;\n }\n if (colCapacityStatus !== -1) {\n const cap = fields[colCapacityStatus] ?? \"\";\n if (cap !== \"Used\") continue;\n }\n\n const instanceType = fields[colInstanceType] ?? \"\";\n const os = fields[colOS] ?? \"\";\n const rawPrice = fields[colPrice] ?? \"\";\n const unit = colUnit !== -1 ? (fields[colUnit] ?? \"Hrs\") : \"Hrs\";\n\n if (!instanceType || !os || !rawPrice) continue;\n\n const priceValue = parseFloat(rawPrice);\n if (!isFinite(priceValue) || priceValue <= 0) continue;\n\n const csvCacheKey = `aws/ec2/${region}/${instanceType.toLowerCase()}/${os.toLowerCase()}`;\n\n const normalized: NormalizedPrice = {\n provider: \"aws\",\n service: \"ec2\",\n resource_type: instanceType,\n region,\n unit,\n price_per_unit: priceValue,\n currency: \"USD\",\n description: `AWS EC2 ${instanceType} (${os}) on-demand`,\n attributes: {\n instance_type: instanceType,\n operating_system: os,\n tenancy: \"Shared\",\n pricing_source: \"live\",\n },\n effective_date: effectiveDate,\n };\n\n this.cache.set(csvCacheKey, normalized, \"aws\", \"ec2\", region, CACHE_TTL);\n cachedCount++;\n }\n }\n\n // Handle any remaining partial line\n if (leftover.trim() && headerFound) {\n const line = leftover.trimEnd();\n if (\n line.includes(\"OnDemand\") &&\n line.includes(\"Compute Instance\")\n ) {\n const fields = parseCsvLine(line);\n const instanceType = fields[colInstanceType] ?? \"\";\n const os = fields[colOS] ?? \"\";\n const rawPrice = fields[colPrice] ?? \"\";\n const unit = colUnit !== -1 ? (fields[colUnit] ?? \"Hrs\") : \"Hrs\";\n const priceValue = parseFloat(rawPrice);\n\n if (instanceType && os && isFinite(priceValue) && priceValue > 0) {\n const csvCacheKey = `aws/ec2/${region}/${instanceType.toLowerCase()}/${os.toLowerCase()}`;\n this.cache.set(\n csvCacheKey,\n {\n provider: \"aws\",\n service: \"ec2\",\n resource_type: instanceType,\n region,\n unit,\n price_per_unit: priceValue,\n currency: \"USD\",\n description: `AWS EC2 ${instanceType} (${os}) on-demand`,\n attributes: {\n instance_type: instanceType,\n operating_system: os,\n tenancy: \"Shared\",\n pricing_source: \"live\",\n },\n effective_date: new Date().toISOString(),\n } satisfies NormalizedPrice,\n \"aws\",\n \"ec2\",\n region,\n CACHE_TTL\n );\n cachedCount++;\n }\n }\n }\n\n logger.debug(\"AWS EC2 CSV streaming complete\", { region, cachedCount });\n return cachedCount > 0;\n } catch (err) {\n if ((err as Error)?.name === \"AbortError\") {\n logger.debug(\"AWS EC2 CSV streaming timed out\", { region });\n } else {\n logger.debug(\"AWS EC2 CSV streaming error\", {\n region,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n return false;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n // -------------------------------------------------------------------------\n // Internal helpers – live API fetch\n // -------------------------------------------------------------------------\n\n private async fetchBulkPricing(\n service: string,\n region: string\n ): Promise<any> {\n const url = `${BULK_PRICING_BASE}/${service}/current/${region}/index.json`;\n logger.debug(\"Fetching AWS bulk pricing\", { url });\n\n const res = await fetch(url, {\n signal: AbortSignal.timeout(30_000),\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} from ${url}`);\n }\n\n return res.json();\n }\n\n private buildCacheKey(\n service: string,\n region: string,\n ...parts: string[]\n ): string {\n return [\"aws\", service, region, ...parts]\n .map((p) => p.toLowerCase())\n .join(\"/\");\n }\n\n // -------------------------------------------------------------------------\n // Internal helpers – extract prices from bulk JSON\n // -------------------------------------------------------------------------\n\n private extractEc2Price(\n bulk: any,\n instanceType: string,\n region: string,\n os: string\n ): NormalizedPrice | null {\n const products: Record<string, any> = bulk?.products ?? {};\n const onDemand: Record<string, any> = bulk?.terms?.OnDemand ?? {};\n\n for (const [sku, product] of Object.entries(products)) {\n const attrs = product?.attributes ?? {};\n if (\n attrs.instanceType === instanceType &&\n (attrs.operatingSystem ?? \"\").toLowerCase() === os.toLowerCase() &&\n attrs.tenancy === \"Shared\" &&\n attrs.capacitystatus === \"Used\"\n ) {\n const priceTerms = onDemand[sku];\n if (priceTerms) {\n return normalizeAwsCompute(product, { terms: { OnDemand: { [sku]: priceTerms } } }, region);\n }\n }\n }\n return null;\n }\n\n private extractRdsPrice(\n bulk: any,\n instanceClass: string,\n region: string,\n engine: string\n ): NormalizedPrice | null {\n const products: Record<string, any> = bulk?.products ?? {};\n const onDemand: Record<string, any> = bulk?.terms?.OnDemand ?? {};\n\n for (const [sku, product] of Object.entries(products)) {\n const attrs = product?.attributes ?? {};\n if (\n attrs.instanceType === instanceClass &&\n (attrs.databaseEngine ?? \"\").toLowerCase().includes(engine.toLowerCase()) &&\n attrs.deploymentOption === \"Single-AZ\"\n ) {\n const priceTerms = onDemand[sku];\n if (priceTerms) {\n return normalizeAwsDatabase(product, { terms: { OnDemand: { [sku]: priceTerms } } }, region);\n }\n }\n }\n return null;\n }\n\n private extractEbsPrice(\n bulk: any,\n volumeType: string,\n region: string\n ): NormalizedPrice | null {\n const products: Record<string, any> = bulk?.products ?? {};\n const onDemand: Record<string, any> = bulk?.terms?.OnDemand ?? {};\n\n for (const [sku, product] of Object.entries(products)) {\n const attrs = product?.attributes ?? {};\n const apiName = (attrs.volumeApiName ?? \"\").toLowerCase();\n if (\n product?.productFamily === \"Storage\" &&\n (apiName === volumeType.toLowerCase() ||\n (attrs.volumeType ?? \"\").toLowerCase() === volumeType.toLowerCase())\n ) {\n const priceTerms = onDemand[sku];\n if (priceTerms) {\n return normalizeAwsStorage(product, { terms: { OnDemand: { [sku]: priceTerms } } }, region);\n }\n }\n }\n return null;\n }\n\n // -------------------------------------------------------------------------\n // Internal helpers – size interpolation\n // -------------------------------------------------------------------------\n\n /**\n * AWS instance sizes follow a predictable doubling pattern:\n * nano → micro → small → medium → large → xlarge → 2xlarge → 4xlarge → 8xlarge → ...\n * Each step roughly doubles the price. Given a known price at one size,\n * we can estimate the price for a missing size in the same family.\n */\n private static readonly SIZE_ORDER: string[] = [\n \"nano\", \"micro\", \"small\", \"medium\", \"large\",\n \"xlarge\", \"2xlarge\", \"4xlarge\", \"8xlarge\", \"12xlarge\",\n \"16xlarge\", \"24xlarge\", \"32xlarge\", \"48xlarge\",\n ];\n\n private interpolatePrice(\n requestedType: string,\n table: Record<string, number>\n ): number | undefined {\n const lower = requestedType.toLowerCase();\n // Split \"m5.2xlarge\" → family \"m5\", size \"2xlarge\"\n // Split \"db.r6g.xlarge\" → family \"db.r6g\", size \"xlarge\"\n const lastDot = lower.lastIndexOf(\".\");\n if (lastDot === -1) return undefined;\n\n const family = lower.slice(0, lastDot);\n const targetSize = lower.slice(lastDot + 1);\n\n const targetIdx = AwsBulkLoader.SIZE_ORDER.indexOf(targetSize);\n if (targetIdx === -1) return undefined;\n\n // Find the closest known size in the same family\n let bestKey: string | undefined;\n let bestIdx = -1;\n let bestDistance = Infinity;\n\n for (const key of Object.keys(table)) {\n const keyLastDot = key.lastIndexOf(\".\");\n if (keyLastDot === -1) continue;\n const keyFamily = key.slice(0, keyLastDot);\n const keySize = key.slice(keyLastDot + 1);\n if (keyFamily !== family) continue;\n\n const keyIdx = AwsBulkLoader.SIZE_ORDER.indexOf(keySize);\n if (keyIdx === -1) continue;\n\n const distance = Math.abs(keyIdx - targetIdx);\n if (distance < bestDistance) {\n bestDistance = distance;\n bestIdx = keyIdx;\n bestKey = key;\n }\n }\n\n if (bestKey === undefined || bestIdx === -1) return undefined;\n\n const knownPrice = table[bestKey]!;\n const steps = targetIdx - bestIdx;\n // Each step doubles (positive = bigger, negative = smaller)\n return knownPrice * Math.pow(2, steps);\n }\n\n // -------------------------------------------------------------------------\n // Internal helpers – fallback hardcoded prices\n // -------------------------------------------------------------------------\n\n private fallbackComputePrice(\n instanceType: string,\n region: string,\n os: string,\n cacheKey: string\n ): NormalizedPrice | null {\n let basePrice = EC2_BASE_PRICES[instanceType.toLowerCase()];\n if (basePrice === undefined) {\n basePrice = this.interpolatePrice(instanceType, EC2_BASE_PRICES) ?? undefined as any;\n }\n if (basePrice === undefined) {\n logger.warn(\"No fallback price found for EC2 instance type\", { instanceType });\n return null;\n }\n\n const multiplier = regionMultiplier(region);\n const result: NormalizedPrice = {\n provider: \"aws\",\n service: \"ec2\",\n resource_type: instanceType,\n region,\n unit: \"Hrs\",\n price_per_unit: basePrice * multiplier,\n currency: \"USD\",\n description: `AWS EC2 ${instanceType} (${os}) – fallback pricing`,\n attributes: {\n instance_type: instanceType,\n operating_system: os,\n tenancy: \"Shared\",\n pricing_source: \"fallback\",\n },\n effective_date: new Date().toISOString(),\n };\n\n this.cache.set(cacheKey, result, \"aws\", \"ec2\", region, CACHE_TTL);\n return result;\n }\n\n private fallbackDatabasePrice(\n instanceClass: string,\n region: string,\n engine: string,\n cacheKey: string\n ): NormalizedPrice | null {\n let basePrice = RDS_BASE_PRICES[instanceClass.toLowerCase()];\n if (basePrice === undefined) {\n basePrice = this.interpolatePrice(instanceClass, RDS_BASE_PRICES) ?? undefined as any;\n }\n if (basePrice === undefined) {\n logger.warn(\"No fallback price found for RDS instance class\", { instanceClass });\n return null;\n }\n\n const multiplier = regionMultiplier(region);\n const result: NormalizedPrice = {\n provider: \"aws\",\n service: \"rds\",\n resource_type: instanceClass,\n region,\n unit: \"Hrs\",\n price_per_unit: basePrice * multiplier,\n currency: \"USD\",\n description: `AWS RDS ${instanceClass} (${engine}) – fallback pricing`,\n attributes: {\n instance_type: instanceClass,\n database_engine: engine,\n deployment_option: \"Single-AZ\",\n pricing_source: \"fallback\",\n },\n effective_date: new Date().toISOString(),\n };\n\n this.cache.set(cacheKey, result, \"aws\", \"rds\", region, CACHE_TTL);\n return result;\n }\n\n private fallbackStoragePrice(\n volumeType: string,\n region: string,\n cacheKey: string\n ): NormalizedPrice | null {\n const basePrice = EBS_BASE_PRICES[volumeType.toLowerCase()];\n if (basePrice === undefined) {\n logger.warn(\"No fallback price found for EBS volume type\", { volumeType });\n return null;\n }\n\n const multiplier = regionMultiplier(region);\n const result: NormalizedPrice = {\n provider: \"aws\",\n service: \"ebs\",\n resource_type: volumeType,\n region,\n unit: \"GB-Mo\",\n price_per_unit: basePrice * multiplier,\n currency: \"USD\",\n description: `AWS EBS ${volumeType} volume – fallback pricing`,\n attributes: {\n volume_type: volumeType,\n pricing_source: \"fallback\",\n },\n effective_date: new Date().toISOString(),\n };\n\n this.cache.set(cacheKey, result, \"aws\", \"ebs\", region, CACHE_TTL);\n return result;\n }\n}\n","import type { NormalizedPrice } from \"../../types/pricing.js\";\n\n/**\n * Convert a single item from the Azure Retail Prices API response into a\n * NormalizedPrice. The raw item shape is documented at:\n * https://learn.microsoft.com/en-us/rest/api/cost-management/retail-prices/azure-retail-prices\n */\n\nexport function normalizeAzureCompute(item: any): NormalizedPrice {\n return {\n provider: \"azure\",\n service: \"virtual-machines\",\n resource_type: item.skuName ?? item.armSkuName ?? \"unknown\",\n region: item.armRegionName ?? item.location ?? \"\",\n unit: item.unitOfMeasure ?? \"1 Hour\",\n price_per_unit: item.retailPrice ?? item.unitPrice ?? 0,\n currency: item.currencyCode ?? \"USD\",\n tier: item.tierMinimumUnits !== undefined ? String(item.tierMinimumUnits) : undefined,\n description: item.productName ?? undefined,\n attributes: {\n sku_name: item.skuName ?? \"\",\n arm_sku_name: item.armSkuName ?? \"\",\n service_name: item.serviceName ?? \"Virtual Machines\",\n product_name: item.productName ?? \"\",\n meter_name: item.meterName ?? \"\",\n pricing_source: \"azure-retail-api\",\n },\n effective_date: item.effectiveStartDate ?? new Date().toISOString(),\n };\n}\n\nexport function normalizeAzureDatabase(item: any): NormalizedPrice {\n return {\n provider: \"azure\",\n service: \"azure-database\",\n resource_type: item.skuName ?? item.armSkuName ?? \"unknown\",\n region: item.armRegionName ?? item.location ?? \"\",\n unit: item.unitOfMeasure ?? \"1 Hour\",\n price_per_unit: item.retailPrice ?? item.unitPrice ?? 0,\n currency: item.currencyCode ?? \"USD\",\n description: item.productName ?? undefined,\n attributes: {\n sku_name: item.skuName ?? \"\",\n service_name: item.serviceName ?? \"\",\n product_name: item.productName ?? \"\",\n meter_name: item.meterName ?? \"\",\n pricing_source: \"azure-retail-api\",\n },\n effective_date: item.effectiveStartDate ?? new Date().toISOString(),\n };\n}\n\nexport function normalizeAzureStorage(item: any): NormalizedPrice {\n return {\n provider: \"azure\",\n service: \"managed-disks\",\n resource_type: item.skuName ?? item.armSkuName ?? \"unknown\",\n region: item.armRegionName ?? item.location ?? \"\",\n unit: item.unitOfMeasure ?? \"1 GiB/Month\",\n price_per_unit: item.retailPrice ?? item.unitPrice ?? 0,\n currency: item.currencyCode ?? \"USD\",\n description: item.productName ?? undefined,\n attributes: {\n sku_name: item.skuName ?? \"\",\n service_name: item.serviceName ?? \"\",\n product_name: item.productName ?? \"\",\n meter_name: item.meterName ?? \"\",\n pricing_source: \"azure-retail-api\",\n },\n effective_date: item.effectiveStartDate ?? new Date().toISOString(),\n };\n}\n","import type { NormalizedPrice } from \"../../types/pricing.js\";\nimport type { PricingCache } from \"../cache.js\";\nimport { logger } from \"../../logger.js\";\nimport {\n normalizeAzureCompute,\n normalizeAzureDatabase,\n normalizeAzureStorage,\n} from \"./azure-normalizer.js\";\n\n// ---------------------------------------------------------------------------\n// Fallback pricing data (approximate eastus on-demand prices, 2024)\n// ---------------------------------------------------------------------------\n\nconst VM_BASE_PRICES: Record<string, number> = {\n \"standard_b1s\": 0.0104,\n \"standard_b1ms\": 0.0207,\n \"standard_b2s\": 0.0416,\n \"standard_b2ms\": 0.0832,\n \"standard_b4ms\": 0.166,\n \"standard_b8ms\": 0.333,\n \"standard_b12ms\": 0.499,\n \"standard_b16ms\": 0.666,\n \"standard_d2s_v4\": 0.096,\n \"standard_d4s_v4\": 0.192,\n \"standard_d8s_v4\": 0.384,\n \"standard_d2s_v5\": 0.096,\n \"standard_d4s_v5\": 0.192,\n \"standard_d8s_v5\": 0.384,\n \"standard_d16s_v5\": 0.768,\n \"standard_d32s_v5\": 1.536,\n \"standard_d2ds_v5\": 0.113,\n \"standard_d4ds_v5\": 0.226,\n \"standard_d8ds_v5\": 0.452,\n \"standard_d2ps_v5\": 0.077,\n \"standard_d4ps_v5\": 0.154,\n \"standard_e2s_v5\": 0.126,\n \"standard_e4s_v5\": 0.252,\n \"standard_e8s_v5\": 0.504,\n \"standard_e16s_v5\": 1.008,\n \"standard_e32s_v5\": 2.016,\n \"standard_e2ds_v5\": 0.144,\n \"standard_e4ds_v5\": 0.288,\n \"standard_f2s_v2\": 0.085,\n \"standard_f4s_v2\": 0.170,\n \"standard_f8s_v2\": 0.340,\n \"standard_f16s_v2\": 0.680,\n \"standard_f32s_v2\": 1.360,\n \"standard_l8s_v3\": 0.624,\n \"standard_l16s_v3\": 1.248,\n \"standard_nc4as_t4_v3\": 0.526,\n \"standard_nc8as_t4_v3\": 0.752,\n \"standard_e2ps_v5\": 0.101,\n \"standard_e4ps_v5\": 0.202,\n \"standard_e8ps_v5\": 0.403,\n};\n\n// Disk prices are per GB/month\nconst DISK_BASE_PRICES: Record<string, number> = {\n \"premium_lrs\": 0.132,\n \"standard_lrs\": 0.04,\n \"standardssd_lrs\": 0.075,\n \"ultrassd_lrs\": 0.12,\n \"premium_lrs_p10\": 0.0052,\n \"premium_lrs_p20\": 0.0100,\n \"premium_lrs_p30\": 0.0192,\n \"premium_lrs_p40\": 0.0373,\n};\n\n// Azure DB for PostgreSQL Flexible prices (per hour)\nconst DB_BASE_PRICES: Record<string, number> = {\n \"burstable_standard_b1ms\": 0.044,\n \"burstable_standard_b2s\": 0.088,\n \"burstable_standard_b4ms\": 0.176,\n \"gp_standard_d2s_v3\": 0.124,\n \"gp_standard_d4s_v3\": 0.248,\n \"gp_standard_d8s_v3\": 0.496,\n \"gp_standard_d16s_v3\": 0.992,\n \"gp_standard_d2ds_v4\": 0.124,\n \"gp_standard_d4ds_v4\": 0.248,\n \"gp_standard_d8ds_v4\": 0.496,\n \"gp_standard_d16ds_v4\": 0.992,\n \"mo_standard_e2ds_v4\": 0.170,\n \"mo_standard_e4ds_v4\": 0.341,\n \"mo_standard_e8ds_v4\": 0.682,\n};\n\n// ALB (Azure Load Balancer) pricing\nconst ALB_HOURLY = 0.025;\nconst ALB_RULE_HOURLY = 0.005;\n\n// Azure NAT Gateway pricing\nconst NAT_HOURLY = 0.045;\nconst NAT_PER_GB = 0.045;\n\n// AKS control plane (paid tier with uptime SLA)\nconst AKS_HOURLY = 0.10;\n\n// ---------------------------------------------------------------------------\n// Regional multipliers relative to eastus\n// ---------------------------------------------------------------------------\n\nconst REGION_MULTIPLIERS: Record<string, number> = {\n eastus: 1.0,\n eastus2: 1.0,\n westus: 1.05,\n westus2: 1.0,\n westus3: 1.02,\n centralus: 1.0,\n northeurope: 1.08,\n westeurope: 1.08,\n uksouth: 1.08,\n ukwest: 1.12,\n southeastasia: 1.12,\n eastasia: 1.12,\n japaneast: 1.10,\n japanwest: 1.12,\n australiaeast: 1.15,\n brazilsouth: 1.25,\n canadacentral: 1.05,\n southafricanorth: 1.15,\n germanywestcentral: 1.10,\n centralindia: 1.08,\n koreacentral: 1.10,\n swedencentral: 1.08,\n italynorth: 1.10,\n uaenorth: 1.12,\n};\n\nfunction regionMultiplier(region: string): number {\n return REGION_MULTIPLIERS[region.toLowerCase()] ?? 1.0;\n}\n\nconst CACHE_TTL = 86400; // 24 hours\n\nconst RETAIL_API_BASE = \"https://prices.azure.com/api/retail/prices\";\n\nexport class AzureRetailClient {\n private cache: PricingCache;\n\n constructor(cache: PricingCache) {\n this.cache = cache;\n }\n\n // -------------------------------------------------------------------------\n // Public API\n // -------------------------------------------------------------------------\n\n async getComputePrice(\n vmSize: string,\n region: string,\n os: string = \"linux\"\n ): Promise<NormalizedPrice | null> {\n const cacheKey = this.buildCacheKey(\"vm\", region, vmSize, os);\n const cached = this.cache.get<NormalizedPrice>(cacheKey);\n if (cached) return cached;\n\n try {\n // OData filter: serviceName eq 'Virtual Machines', armRegionName eq '{region}',\n // skuName contains vmSize, priceType eq 'Consumption'\n const armRegion = region.toLowerCase().replace(/\\s+/g, \"\");\n const filter = this.buildODataFilter(\"Virtual Machines\", armRegion, vmSize, true);\n const items = await this.queryPricing(filter);\n\n // Pick the best match: prefer the one that's exactly the right OS\n const match = this.pickVmItem(items, vmSize, os);\n if (match) {\n const result = normalizeAzureCompute(match);\n this.cache.set(cacheKey, result, \"azure\", \"vm\", region, CACHE_TTL);\n return result;\n }\n } catch (err) {\n logger.debug(\"Azure Retail API VM fetch failed, using fallback\", {\n region,\n vmSize,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n\n return this.fallbackComputePrice(vmSize, region, os, cacheKey);\n }\n\n async getDatabasePrice(\n tier: string,\n region: string,\n engine: string = \"PostgreSQL\"\n ): Promise<NormalizedPrice | null> {\n const cacheKey = this.buildCacheKey(\"db\", region, tier, engine);\n const cached = this.cache.get<NormalizedPrice>(cacheKey);\n if (cached) return cached;\n\n try {\n const armRegion = region.toLowerCase().replace(/\\s+/g, \"\");\n // Azure DB service names vary: \"Azure Database for PostgreSQL\", etc.\n const serviceName = `Azure Database for ${engine}`;\n const filter = this.buildODataFilter(serviceName, armRegion, tier);\n const items = await this.queryPricing(filter);\n\n if (items.length > 0) {\n const result = normalizeAzureDatabase(items[0]);\n this.cache.set(cacheKey, result, \"azure\", \"db\", region, CACHE_TTL);\n return result;\n }\n } catch (err) {\n logger.debug(\"Azure Retail API DB fetch failed, using fallback\", {\n region,\n tier,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n\n return this.fallbackDatabasePrice(tier, region, engine, cacheKey);\n }\n\n async getStoragePrice(\n diskType: string,\n region: string\n ): Promise<NormalizedPrice | null> {\n const cacheKey = this.buildCacheKey(\"disk\", region, diskType);\n const cached = this.cache.get<NormalizedPrice>(cacheKey);\n if (cached) return cached;\n\n try {\n const armRegion = region.toLowerCase().replace(/\\s+/g, \"\");\n const filter = this.buildODataFilter(\"Storage\", armRegion, diskType);\n const items = await this.queryPricing(filter);\n\n if (items.length > 0) {\n const result = normalizeAzureStorage(items[0]);\n this.cache.set(cacheKey, result, \"azure\", \"storage\", region, CACHE_TTL);\n return result;\n }\n } catch (err) {\n logger.debug(\"Azure Retail API storage fetch failed, using fallback\", {\n region,\n diskType,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n\n return this.fallbackStoragePrice(diskType, region, cacheKey);\n }\n\n async getLoadBalancerPrice(region: string): Promise<NormalizedPrice | null> {\n const multiplier = regionMultiplier(region);\n return {\n provider: \"azure\",\n service: \"load-balancer\",\n resource_type: \"standard\",\n region,\n unit: \"1 Hour\",\n price_per_unit: ALB_HOURLY * multiplier,\n currency: \"USD\",\n description: \"Azure Load Balancer Standard (hourly + per rule)\",\n attributes: {\n rule_hourly_price: String(ALB_RULE_HOURLY * multiplier),\n pricing_model: \"fixed_plus_rules\",\n },\n effective_date: new Date().toISOString(),\n };\n }\n\n async getNatGatewayPrice(region: string): Promise<NormalizedPrice | null> {\n const multiplier = regionMultiplier(region);\n return {\n provider: \"azure\",\n service: \"nat-gateway\",\n resource_type: \"nat-gateway\",\n region,\n unit: \"1 Hour\",\n price_per_unit: NAT_HOURLY * multiplier,\n currency: \"USD\",\n description: \"Azure NAT Gateway (hourly + data processed)\",\n attributes: {\n per_gb_price: String(NAT_PER_GB * multiplier),\n },\n effective_date: new Date().toISOString(),\n };\n }\n\n async getKubernetesPrice(region: string): Promise<NormalizedPrice | null> {\n const multiplier = regionMultiplier(region);\n return {\n provider: \"azure\",\n service: \"aks\",\n resource_type: \"cluster\",\n region,\n unit: \"1 Hour\",\n price_per_unit: AKS_HOURLY * multiplier,\n currency: \"USD\",\n description: \"Azure Kubernetes Service (uptime SLA tier, per cluster/hour)\",\n attributes: {},\n effective_date: new Date().toISOString(),\n };\n }\n\n // -------------------------------------------------------------------------\n // Internal helpers – live API\n // -------------------------------------------------------------------------\n\n private async queryPricing(filter: string): Promise<any[]> {\n const allItems: any[] = [];\n let url: string | null = `${RETAIL_API_BASE}?api-version=2023-01-01-preview&$filter=${encodeURIComponent(filter)}`;\n logger.debug(\"Querying Azure Retail Prices API\", { filter });\n\n let pages = 0;\n while (url && pages < 10) {\n const res = await fetch(url, {\n signal: AbortSignal.timeout(30_000),\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} from Azure Retail API`);\n }\n\n const json: any = await res.json();\n allItems.push(...(json?.Items ?? []));\n url = json?.NextPageLink ?? null;\n pages++;\n }\n\n return allItems;\n }\n\n private buildODataFilter(\n service: string,\n armRegion: string,\n skuName?: string,\n exactArmSku?: boolean\n ): string {\n let filter = `serviceName eq '${service}' and armRegionName eq '${armRegion}' and priceType eq 'Consumption'`;\n if (skuName) {\n if (exactArmSku) {\n filter += ` and armSkuName eq '${skuName}'`;\n } else {\n filter += ` and contains(skuName, '${skuName}')`;\n }\n }\n return filter;\n }\n\n private buildCacheKey(\n service: string,\n region: string,\n ...parts: string[]\n ): string {\n return [\"azure\", service, region, ...parts]\n .map((p) => p.toLowerCase())\n .join(\"/\");\n }\n\n /**\n * From the API response items, pick the item that best matches the desired\n * VM size and OS. Prefers exact skuName matches and the correct OS suffix\n * (\"Windows\" vs everything else being Linux).\n */\n private pickVmItem(items: any[], vmSize: string, os: string): any | null {\n if (items.length === 0) return null;\n const vmLower = vmSize.toLowerCase();\n const isWindows = os.toLowerCase().includes(\"windows\");\n\n // Prefer exact sku match with the right OS\n for (const item of items) {\n const skuLower = (item.skuName ?? \"\").toLowerCase();\n const hasWindows = skuLower.includes(\"windows\");\n if (\n skuLower.includes(vmLower) &&\n ((isWindows && hasWindows) || (!isWindows && !hasWindows))\n ) {\n return item;\n }\n }\n\n // Fallback: return the first item\n return items[0];\n }\n\n // -------------------------------------------------------------------------\n // Internal helpers – size interpolation\n // -------------------------------------------------------------------------\n\n /**\n * Azure VM sizes embed vCPU count as a number: Standard_D2s_v5 → 2 vCPUs.\n * Doubling the number roughly doubles the price. Find the nearest known\n * size in the same family/suffix and scale proportionally.\n */\n private interpolateVmPrice(\n vmSize: string,\n table: Record<string, number>\n ): number | undefined {\n const key = vmSize.toLowerCase().replace(/\\s+/g, \"_\");\n // Match pattern like \"standard_d2s_v5\" → prefix \"standard_d\", num 2, suffix \"s_v5\"\n const match = key.match(/^(.+?)(\\d+)(.*?)$/);\n if (!match) return undefined;\n\n const [, prefix, numStr, suffix] = match;\n const targetNum = parseInt(numStr, 10);\n if (isNaN(targetNum) || targetNum === 0) return undefined;\n\n let bestKey: string | undefined;\n let bestNum = 0;\n let bestDistance = Infinity;\n\n for (const candidate of Object.keys(table)) {\n const candMatch = candidate.match(/^(.+?)(\\d+)(.*?)$/);\n if (!candMatch) continue;\n const [, cPrefix, cNumStr, cSuffix] = candMatch;\n if (cPrefix !== prefix || cSuffix !== suffix) continue;\n\n const cNum = parseInt(cNumStr, 10);\n if (isNaN(cNum) || cNum === 0) continue;\n\n const distance = Math.abs(cNum - targetNum);\n if (distance < bestDistance) {\n bestDistance = distance;\n bestNum = cNum;\n bestKey = candidate;\n }\n }\n\n if (bestKey === undefined || bestNum === 0) return undefined;\n return table[bestKey]! * (targetNum / bestNum);\n }\n\n /**\n * Azure DB tier names embed a vCPU number similarly to VM sizes.\n * e.g. \"gp_standard_d2s_v3\" → \"gp_standard_d4s_v3\" doubles.\n */\n private interpolateDbPrice(\n tier: string,\n table: Record<string, number>\n ): number | undefined {\n const key = tier.toLowerCase().replace(/\\s+/g, \"_\").replace(/-/g, \"_\");\n const match = key.match(/^(.+?)(\\d+)(.*?)$/);\n if (!match) return undefined;\n\n const [, prefix, numStr, suffix] = match;\n const targetNum = parseInt(numStr, 10);\n if (isNaN(targetNum) || targetNum === 0) return undefined;\n\n let bestKey: string | undefined;\n let bestNum = 0;\n let bestDistance = Infinity;\n\n for (const candidate of Object.keys(table)) {\n const candMatch = candidate.match(/^(.+?)(\\d+)(.*?)$/);\n if (!candMatch) continue;\n const [, cPrefix, cNumStr, cSuffix] = candMatch;\n if (cPrefix !== prefix || cSuffix !== suffix) continue;\n\n const cNum = parseInt(cNumStr, 10);\n if (isNaN(cNum) || cNum === 0) continue;\n\n const distance = Math.abs(cNum - targetNum);\n if (distance < bestDistance) {\n bestDistance = distance;\n bestNum = cNum;\n bestKey = candidate;\n }\n }\n\n if (bestKey === undefined || bestNum === 0) return undefined;\n return table[bestKey]! * (targetNum / bestNum);\n }\n\n // -------------------------------------------------------------------------\n // Internal helpers – fallback hardcoded prices\n // -------------------------------------------------------------------------\n\n private fallbackComputePrice(\n vmSize: string,\n region: string,\n os: string,\n cacheKey: string\n ): NormalizedPrice | null {\n const key = vmSize.toLowerCase().replace(/\\s+/g, \"_\");\n let basePrice = VM_BASE_PRICES[key];\n if (basePrice === undefined) {\n basePrice = this.interpolateVmPrice(vmSize, VM_BASE_PRICES) ?? undefined as any;\n }\n if (basePrice === undefined) {\n logger.warn(\"No fallback price found for Azure VM size\", { vmSize });\n return null;\n }\n\n const multiplier = regionMultiplier(region);\n const result: NormalizedPrice = {\n provider: \"azure\",\n service: \"virtual-machines\",\n resource_type: vmSize,\n region,\n unit: \"1 Hour\",\n price_per_unit: basePrice * multiplier,\n currency: \"USD\",\n description: `Azure VM ${vmSize} (${os}) – fallback pricing`,\n attributes: {\n sku_name: vmSize,\n operating_system: os,\n pricing_source: \"fallback\",\n },\n effective_date: new Date().toISOString(),\n };\n\n this.cache.set(cacheKey, result, \"azure\", \"vm\", region, CACHE_TTL);\n return result;\n }\n\n private fallbackDatabasePrice(\n tier: string,\n region: string,\n engine: string,\n cacheKey: string\n ): NormalizedPrice | null {\n const key = tier.toLowerCase().replace(/\\s+/g, \"_\").replace(/-/g, \"_\");\n let basePrice = DB_BASE_PRICES[key];\n if (basePrice === undefined) {\n basePrice = this.interpolateDbPrice(tier, DB_BASE_PRICES) ?? undefined as any;\n }\n if (basePrice === undefined) {\n logger.warn(\"No fallback price found for Azure DB tier\", { tier });\n return null;\n }\n\n const multiplier = regionMultiplier(region);\n const result: NormalizedPrice = {\n provider: \"azure\",\n service: \"azure-database\",\n resource_type: tier,\n region,\n unit: \"1 Hour\",\n price_per_unit: basePrice * multiplier,\n currency: \"USD\",\n description: `Azure Database for ${engine} ${tier} – fallback pricing`,\n attributes: {\n tier,\n engine,\n pricing_source: \"fallback\",\n },\n effective_date: new Date().toISOString(),\n };\n\n this.cache.set(cacheKey, result, \"azure\", \"db\", region, CACHE_TTL);\n return result;\n }\n\n private fallbackStoragePrice(\n diskType: string,\n region: string,\n cacheKey: string\n ): NormalizedPrice | null {\n const key = diskType.toLowerCase().replace(/\\s+/g, \"_\").replace(/-/g, \"_\");\n const basePrice = DISK_BASE_PRICES[key];\n if (basePrice === undefined) {\n logger.warn(\"No fallback price found for Azure disk type\", { diskType });\n return null;\n }\n\n const multiplier = regionMultiplier(region);\n const result: NormalizedPrice = {\n provider: \"azure\",\n service: \"managed-disks\",\n resource_type: diskType,\n region,\n unit: \"1 GiB/Month\",\n price_per_unit: basePrice * multiplier,\n currency: \"USD\",\n description: `Azure Managed Disk ${diskType} – fallback pricing`,\n attributes: {\n disk_type: diskType,\n pricing_source: \"fallback\",\n },\n effective_date: new Date().toISOString(),\n };\n\n this.cache.set(cacheKey, result, \"azure\", \"storage\", region, CACHE_TTL);\n return result;\n }\n}\n","import type { NormalizedPrice } from \"../../types/pricing.js\";\n\n/**\n * Convert bundled GCP pricing data (plain numbers from JSON files) into the\n * canonical NormalizedPrice shape.\n */\n\nexport function normalizeGcpCompute(\n machineType: string,\n hourlyPrice: number,\n region: string\n): NormalizedPrice {\n return {\n provider: \"gcp\",\n service: \"compute-engine\",\n resource_type: machineType,\n region,\n unit: \"h\",\n price_per_unit: hourlyPrice,\n currency: \"USD\",\n description: `GCP Compute Engine ${machineType}`,\n attributes: {\n machine_type: machineType,\n pricing_source: \"bundled\",\n },\n effective_date: new Date().toISOString(),\n };\n}\n\nexport function normalizeGcpDatabase(\n tier: string,\n hourlyPrice: number,\n region: string\n): NormalizedPrice {\n return {\n provider: \"gcp\",\n service: \"cloud-sql\",\n resource_type: tier,\n region,\n unit: \"h\",\n price_per_unit: hourlyPrice,\n currency: \"USD\",\n description: `GCP Cloud SQL ${tier}`,\n attributes: {\n tier,\n pricing_source: \"bundled\",\n },\n effective_date: new Date().toISOString(),\n };\n}\n\nexport function normalizeGcpStorage(\n storageClass: string,\n pricePerGb: number,\n region: string\n): NormalizedPrice {\n return {\n provider: \"gcp\",\n service: \"cloud-storage\",\n resource_type: storageClass,\n region,\n unit: \"GiBy.mo\",\n price_per_unit: pricePerGb,\n currency: \"USD\",\n description: `GCP Cloud Storage ${storageClass}`,\n attributes: {\n storage_class: storageClass,\n pricing_source: \"bundled\",\n },\n effective_date: new Date().toISOString(),\n };\n}\n\nexport function normalizeGcpDisk(\n diskType: string,\n pricePerGb: number,\n region: string\n): NormalizedPrice {\n return {\n provider: \"gcp\",\n service: \"persistent-disk\",\n resource_type: diskType,\n region,\n unit: \"GiBy.mo\",\n price_per_unit: pricePerGb,\n currency: \"USD\",\n description: `GCP Persistent Disk ${diskType}`,\n attributes: {\n disk_type: diskType,\n pricing_source: \"bundled\",\n },\n effective_date: new Date().toISOString(),\n };\n}\n","import type { NormalizedPrice } from \"../../types/pricing.js\";\nimport { logger } from \"../../logger.js\";\nimport {\n getGcpComputePricing,\n getGcpSqlPricing,\n getGcpStoragePricing,\n getGcpDiskPricing,\n} from \"../../data/loader.js\";\nimport {\n normalizeGcpCompute,\n normalizeGcpDatabase,\n normalizeGcpStorage,\n normalizeGcpDisk,\n} from \"./gcp-normalizer.js\";\n\n// ---------------------------------------------------------------------------\n// GCP-specific infrastructure pricing (not in bundled data files)\n// ---------------------------------------------------------------------------\n\n// Cloud Load Balancing (per forwarding rule / hour + per GB data processed)\nconst LB_FORWARDING_RULE_HOURLY = 0.025;\nconst LB_PER_GB = 0.008;\n\n// Cloud NAT\nconst NAT_HOURLY = 0.044;\nconst NAT_PER_GB = 0.045;\n\n// GKE control plane\n// Standard cluster: $0.10/hr\n// Autopilot: $0.0445/vCPU/hr estimate (actual billing is per-pod resources;\n// this approximation provides a per-cluster ballpark for cost comparisons)\nconst GKE_STANDARD_HOURLY = 0.10;\nconst GKE_AUTOPILOT_VCPU_HOURLY = 0.0445;\n\nexport class GcpBundledLoader {\n // -------------------------------------------------------------------------\n // Public API\n // -------------------------------------------------------------------------\n\n async getComputePrice(\n machineType: string,\n region: string\n ): Promise<NormalizedPrice | null> {\n try {\n const pricing = getGcpComputePricing();\n const regionPrices = pricing[region];\n\n if (!regionPrices) {\n logger.debug(\"GCP compute: region not found in bundled data\", {\n region,\n machineType,\n });\n return null;\n }\n\n const price = regionPrices[machineType];\n if (price === undefined) {\n logger.debug(\"GCP compute: machine type not found in bundled data\", {\n region,\n machineType,\n });\n return null;\n }\n\n return normalizeGcpCompute(machineType, price, region);\n } catch (err) {\n logger.error(\"GCP compute pricing load error\", {\n machineType,\n region,\n err: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n }\n\n async getDatabasePrice(\n tier: string,\n region: string\n ): Promise<NormalizedPrice | null> {\n try {\n const pricing = getGcpSqlPricing();\n const regionPrices = pricing[region];\n\n if (!regionPrices) {\n logger.debug(\"GCP SQL: region not found in bundled data\", {\n region,\n tier,\n });\n return null;\n }\n\n // \"storage_per_gb\" and \"ha_multiplier\" are metadata keys, not tiers\n const price = regionPrices[tier];\n if (price === undefined || tier === \"storage_per_gb\" || tier === \"ha_multiplier\") {\n logger.debug(\"GCP SQL: tier not found in bundled data\", {\n region,\n tier,\n });\n return null;\n }\n\n return normalizeGcpDatabase(tier, price, region);\n } catch (err) {\n logger.error(\"GCP SQL pricing load error\", {\n tier,\n region,\n err: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n }\n\n async getStoragePrice(\n storageClass: string,\n region: string\n ): Promise<NormalizedPrice | null> {\n try {\n const pricing = getGcpStoragePricing();\n const regionPrices = pricing[region];\n\n if (!regionPrices) {\n logger.debug(\"GCP Storage: region not found in bundled data\", {\n region,\n storageClass,\n });\n return null;\n }\n\n const classKey = storageClass.toUpperCase() as keyof typeof regionPrices;\n const price = regionPrices[classKey];\n if (price === undefined) {\n logger.debug(\"GCP Storage: storage class not found in bundled data\", {\n region,\n storageClass,\n });\n return null;\n }\n\n return normalizeGcpStorage(storageClass.toUpperCase(), price, region);\n } catch (err) {\n logger.error(\"GCP Storage pricing load error\", {\n storageClass,\n region,\n err: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n }\n\n async getDiskPrice(\n diskType: string,\n region: string\n ): Promise<NormalizedPrice | null> {\n try {\n const pricing = getGcpDiskPricing();\n const regionPrices = pricing[region];\n\n if (!regionPrices) {\n logger.debug(\"GCP Disk: region not found in bundled data\", {\n region,\n diskType,\n });\n return null;\n }\n\n const diskKey = diskType as keyof typeof regionPrices;\n const price = regionPrices[diskKey];\n if (price === undefined) {\n logger.debug(\"GCP Disk: disk type not found in bundled data\", {\n region,\n diskType,\n });\n return null;\n }\n\n return normalizeGcpDisk(diskType, price, region);\n } catch (err) {\n logger.error(\"GCP Disk pricing load error\", {\n diskType,\n region,\n err: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n }\n\n async getLoadBalancerPrice(region: string): Promise<NormalizedPrice | null> {\n return {\n provider: \"gcp\",\n service: \"cloud-load-balancing\",\n resource_type: \"forwarding-rule\",\n region,\n unit: \"h\",\n price_per_unit: LB_FORWARDING_RULE_HOURLY,\n currency: \"USD\",\n description: \"GCP Cloud Load Balancing forwarding rule (per hour + data processed)\",\n attributes: {\n per_gb_price: String(LB_PER_GB),\n },\n effective_date: new Date().toISOString(),\n };\n }\n\n async getNatGatewayPrice(region: string): Promise<NormalizedPrice | null> {\n return {\n provider: \"gcp\",\n service: \"cloud-nat\",\n resource_type: \"nat-gateway\",\n region,\n unit: \"h\",\n price_per_unit: NAT_HOURLY,\n currency: \"USD\",\n description: \"GCP Cloud NAT (per gateway/hour + data processed)\",\n attributes: {\n per_gb_price: String(NAT_PER_GB),\n },\n effective_date: new Date().toISOString(),\n };\n }\n\n async getKubernetesPrice(\n region: string,\n mode: \"standard\" | \"autopilot\" = \"standard\"\n ): Promise<NormalizedPrice | null> {\n const hourlyPrice =\n mode === \"autopilot\" ? GKE_AUTOPILOT_VCPU_HOURLY : GKE_STANDARD_HOURLY;\n\n return {\n provider: \"gcp\",\n service: \"gke\",\n resource_type: \"cluster\",\n region,\n unit: \"h\",\n price_per_unit: hourlyPrice,\n currency: \"USD\",\n description:\n mode === \"autopilot\"\n ? \"GCP GKE Autopilot cluster (estimated per-vCPU/hr; actual billing is per-pod resources)\"\n : \"GCP GKE Standard cluster (per cluster/hour)\",\n attributes: {\n mode,\n ...(mode === \"autopilot\" && {\n pricing_model: \"per_vcpu_hour\",\n pricing_note: \"Autopilot charges per pod vCPU and memory. This price is a per-vCPU/hr approximation for cluster-level cost estimation.\",\n }),\n },\n effective_date: new Date().toISOString(),\n };\n }\n}\n","import type { NormalizedPrice } from \"../types/pricing.js\";\nimport type { CloudProvider } from \"../types/resources.js\";\nimport type { CloudCostConfig } from \"../types/config.js\";\nimport { PricingCache } from \"./cache.js\";\nimport { AwsBulkLoader } from \"./aws/bulk-loader.js\";\nimport { AzureRetailClient } from \"./azure/retail-client.js\";\nimport { GcpBundledLoader } from \"./gcp/bundled-loader.js\";\nimport { logger } from \"../logger.js\";\n\n// ---------------------------------------------------------------------------\n// PricingProvider interface\n// ---------------------------------------------------------------------------\n\n/**\n * Common interface that all cloud provider pricing implementations must satisfy.\n * Each method returns null when no pricing information is available for the\n * requested combination of parameters.\n */\nexport interface PricingProvider {\n getComputePrice(\n instanceType: string,\n region: string,\n os?: string\n ): Promise<NormalizedPrice | null>;\n\n getDatabasePrice(\n instanceType: string,\n region: string,\n engine?: string\n ): Promise<NormalizedPrice | null>;\n\n getStoragePrice(\n storageType: string,\n region: string,\n sizeGb?: number\n ): Promise<NormalizedPrice | null>;\n\n getLoadBalancerPrice(\n type: string,\n region: string\n ): Promise<NormalizedPrice | null>;\n\n getNatGatewayPrice(region: string): Promise<NormalizedPrice | null>;\n\n getKubernetesPrice(region: string): Promise<NormalizedPrice | null>;\n}\n\n// ---------------------------------------------------------------------------\n// Provider adapters – thin wrappers that satisfy PricingProvider on top of\n// the underlying loader / client classes.\n// ---------------------------------------------------------------------------\n\nclass AwsProvider implements PricingProvider {\n private loader: AwsBulkLoader;\n\n constructor(cache: PricingCache) {\n this.loader = new AwsBulkLoader(cache);\n }\n\n getComputePrice(\n instanceType: string,\n region: string,\n os?: string\n ): Promise<NormalizedPrice | null> {\n return this.loader.getComputePrice(instanceType, region, os);\n }\n\n getDatabasePrice(\n instanceType: string,\n region: string,\n engine?: string\n ): Promise<NormalizedPrice | null> {\n return this.loader.getDatabasePrice(instanceType, region, engine);\n }\n\n getStoragePrice(\n storageType: string,\n region: string,\n _sizeGb?: number\n ): Promise<NormalizedPrice | null> {\n return this.loader.getStoragePrice(storageType, region);\n }\n\n getLoadBalancerPrice(\n _type: string,\n region: string\n ): Promise<NormalizedPrice | null> {\n return this.loader.getLoadBalancerPrice(region);\n }\n\n getNatGatewayPrice(region: string): Promise<NormalizedPrice | null> {\n return this.loader.getNatGatewayPrice(region);\n }\n\n getKubernetesPrice(region: string): Promise<NormalizedPrice | null> {\n return this.loader.getKubernetesPrice(region);\n }\n}\n\nclass AzureProvider implements PricingProvider {\n private client: AzureRetailClient;\n\n constructor(cache: PricingCache) {\n this.client = new AzureRetailClient(cache);\n }\n\n getComputePrice(\n instanceType: string,\n region: string,\n os?: string\n ): Promise<NormalizedPrice | null> {\n return this.client.getComputePrice(instanceType, region, os);\n }\n\n getDatabasePrice(\n instanceType: string,\n region: string,\n engine?: string\n ): Promise<NormalizedPrice | null> {\n return this.client.getDatabasePrice(instanceType, region, engine);\n }\n\n getStoragePrice(\n storageType: string,\n region: string,\n _sizeGb?: number\n ): Promise<NormalizedPrice | null> {\n return this.client.getStoragePrice(storageType, region);\n }\n\n getLoadBalancerPrice(\n _type: string,\n region: string\n ): Promise<NormalizedPrice | null> {\n return this.client.getLoadBalancerPrice(region);\n }\n\n getNatGatewayPrice(region: string): Promise<NormalizedPrice | null> {\n return this.client.getNatGatewayPrice(region);\n }\n\n getKubernetesPrice(region: string): Promise<NormalizedPrice | null> {\n return this.client.getKubernetesPrice(region);\n }\n}\n\nclass GcpProvider implements PricingProvider {\n private loader: GcpBundledLoader;\n\n constructor() {\n this.loader = new GcpBundledLoader();\n }\n\n getComputePrice(\n instanceType: string,\n region: string,\n _os?: string\n ): Promise<NormalizedPrice | null> {\n return this.loader.getComputePrice(instanceType, region);\n }\n\n getDatabasePrice(\n instanceType: string,\n region: string,\n _engine?: string\n ): Promise<NormalizedPrice | null> {\n return this.loader.getDatabasePrice(instanceType, region);\n }\n\n getStoragePrice(\n storageType: string,\n region: string,\n _sizeGb?: number\n ): Promise<NormalizedPrice | null> {\n // Treat the storageType as a Cloud Storage class first; if it looks like\n // a disk type (pd-*) fall through to getDiskPrice.\n if (storageType.startsWith(\"pd-\")) {\n return this.loader.getDiskPrice(storageType, region);\n }\n return this.loader.getStoragePrice(storageType, region);\n }\n\n getLoadBalancerPrice(\n _type: string,\n region: string\n ): Promise<NormalizedPrice | null> {\n return this.loader.getLoadBalancerPrice(region);\n }\n\n getNatGatewayPrice(region: string): Promise<NormalizedPrice | null> {\n return this.loader.getNatGatewayPrice(region);\n }\n\n getKubernetesPrice(region: string): Promise<NormalizedPrice | null> {\n return this.loader.getKubernetesPrice(region);\n }\n}\n\n// ---------------------------------------------------------------------------\n// PricingEngine – unified entry point\n// ---------------------------------------------------------------------------\n\n/**\n * PricingEngine holds one PricingProvider instance per cloud provider and\n * exposes a generic getPrice() method that dispatches to the right backend.\n *\n * The engine is intentionally thin: it does not contain pricing logic itself,\n * only routing and provider lifecycle management.\n */\nexport class PricingEngine {\n private providers: Map<CloudProvider, PricingProvider> = new Map();\n\n constructor(cache: PricingCache, _config: CloudCostConfig) {\n this.providers.set(\"aws\", new AwsProvider(cache));\n this.providers.set(\"azure\", new AzureProvider(cache));\n this.providers.set(\"gcp\", new GcpProvider());\n }\n\n /**\n * Return the PricingProvider for a specific cloud provider.\n * Throws if the provider is not registered (should never happen for the\n * three known providers).\n */\n getProvider(provider: CloudProvider): PricingProvider {\n const p = this.providers.get(provider);\n if (!p) {\n throw new Error(`Unknown cloud provider: ${provider}`);\n }\n return p;\n }\n\n /**\n * Generic price lookup that maps service/resourceType strings to the\n * appropriate method on the underlying PricingProvider.\n *\n * Supported service values (case-insensitive):\n * compute, ec2, vm, instance → getComputePrice\n * database, rds, sql, db → getDatabasePrice\n * storage, ebs, disk, gcs → getStoragePrice\n * lb, load-balancer, alb, nlb → getLoadBalancerPrice\n * nat, nat-gateway → getNatGatewayPrice\n * k8s, kubernetes, eks, aks, gke → getKubernetesPrice\n */\n async getPrice(\n provider: CloudProvider,\n service: string,\n resourceType: string,\n region: string,\n attributes: Record<string, string> = {}\n ): Promise<NormalizedPrice | null> {\n const p = this.getProvider(provider);\n const svc = service.toLowerCase();\n\n logger.debug(\"PricingEngine.getPrice\", {\n provider,\n service,\n resourceType,\n region,\n });\n\n if (\n svc === \"compute\" ||\n svc === \"ec2\" ||\n svc === \"vm\" ||\n svc === \"instance\" ||\n svc === \"virtual-machines\"\n ) {\n return p.getComputePrice(resourceType, region, attributes.os);\n }\n\n if (\n svc === \"database\" ||\n svc === \"rds\" ||\n svc === \"sql\" ||\n svc === \"db\" ||\n svc === \"cloud-sql\" ||\n svc === \"azure-database\"\n ) {\n return p.getDatabasePrice(resourceType, region, attributes.engine);\n }\n\n if (\n svc === \"storage\" ||\n svc === \"ebs\" ||\n svc === \"disk\" ||\n svc === \"gcs\" ||\n svc === \"managed-disks\" ||\n svc === \"persistent-disk\" ||\n svc === \"cloud-storage\"\n ) {\n const sizeGb = attributes.size_gb\n ? parseFloat(attributes.size_gb)\n : undefined;\n return p.getStoragePrice(resourceType, region, sizeGb);\n }\n\n if (\n svc === \"lb\" ||\n svc === \"load-balancer\" ||\n svc === \"alb\" ||\n svc === \"nlb\" ||\n svc === \"elb\" ||\n svc === \"cloud-load-balancing\"\n ) {\n return p.getLoadBalancerPrice(resourceType, region);\n }\n\n if (svc === \"nat\" || svc === \"nat-gateway\" || svc === \"cloud-nat\") {\n return p.getNatGatewayPrice(region);\n }\n\n if (\n svc === \"k8s\" ||\n svc === \"kubernetes\" ||\n svc === \"eks\" ||\n svc === \"aks\" ||\n svc === \"gke\"\n ) {\n return p.getKubernetesPrice(region);\n }\n\n logger.warn(\"PricingEngine: unrecognised service\", { service, provider });\n return null;\n }\n}\n","import { z } from \"zod\";\nimport { parseTerraform } from \"../parsers/index.js\";\n\n// ---------------------------------------------------------------------------\n// Schema\n// ---------------------------------------------------------------------------\n\nexport const analyzeTerraformSchema = z.object({\n files: z\n .array(\n z.object({\n path: z.string().describe(\"File path\"),\n content: z.string().describe(\"File content (HCL)\"),\n })\n )\n .describe(\"Terraform files to analyze\"),\n tfvars: z\n .string()\n .optional()\n .describe(\"Contents of terraform.tfvars file\"),\n});\n\n// ---------------------------------------------------------------------------\n// Handler\n// ---------------------------------------------------------------------------\n\n/**\n * Parse one or more Terraform HCL files and return the resulting\n * ResourceInventory as a plain object suitable for JSON serialisation.\n *\n * parse_warnings is promoted to the top of the response so callers can\n * immediately identify resources that could not be fully resolved (e.g.\n * module blocks not expanded, count/for_each unresolved).\n */\nexport async function analyzeTerraform(\n params: z.infer<typeof analyzeTerraformSchema>\n): Promise<object> {\n const inventory = await parseTerraform(params.files, params.tfvars);\n\n // Reorder so parse_warnings appears first in serialised output for\n // immediate visibility to callers inspecting the raw JSON.\n const { parse_warnings, ...rest } = inventory;\n\n return {\n parse_warnings,\n has_warnings: parse_warnings.length > 0,\n ...rest,\n } as unknown as object;\n}\n","import { parse } from \"@cdktf/hcl2json\";\nimport { logger } from \"../logger.js\";\n\n/**\n * Convert raw HCL content into a plain JavaScript object using the\n * @cdktf/hcl2json WASM-backed parser. The filename parameter is used only for\n * error reporting and diagnostics inside the parser; it does not need to be an\n * actual path on disk.\n *\n * The returned shape mirrors the Terraform HCL block structure:\n * {\n * provider: { aws: [{ region: \"us-east-1\" }] },\n * resource: { aws_instance: { name: [{ instance_type: \"t3.micro\", ... }] } },\n * variable: { region: [{ default: \"us-east-1\" }] },\n * ...\n * }\n */\nexport async function parseHclToJson(\n hclContent: string,\n filename = \"main.tf\"\n): Promise<Record<string, unknown>> {\n if (!hclContent.trim()) {\n logger.debug(\"Received empty HCL content, returning empty object\", {\n filename,\n });\n return {};\n }\n\n try {\n const result = await parse(filename, hclContent);\n logger.debug(\"Parsed HCL successfully\", { filename });\n return result as Record<string, unknown>;\n } catch (err) {\n const message =\n err instanceof Error ? err.message : String(err);\n\n logger.error(\"Failed to parse HCL\", { filename, error: message });\n\n throw new Error(\n `HCL parse error in \"${filename}\": ${message}`\n );\n }\n}\n","import { logger } from \"../logger.js\";\n\n/**\n * Collect variable defaults from parsed HCL JSON and merge in any overrides\n * supplied via a .tfvars file. The resulting map is a flat key->value record\n * ready for substitution into attribute strings.\n *\n * HCL JSON structure for variables:\n * { variable: { \"name\": [{ default: <value>, type: \"string\" }] } }\n */\nexport function resolveVariables(\n hclJson: Record<string, unknown>,\n tfvarsContent?: string\n): Record<string, unknown> {\n const defaults = extractVariableDefaults(hclJson);\n const overrides = tfvarsContent ? parseTfvars(tfvarsContent) : {};\n\n const resolved = { ...defaults, ...overrides };\n\n logger.debug(\"Resolved variables\", {\n defaultCount: Object.keys(defaults).length,\n overrideCount: Object.keys(overrides).length,\n });\n\n return resolved;\n}\n\n/**\n * Walk the `variable` block in parsed HCL JSON and build a map of\n * variable name -> default value for any variable that declares one.\n */\nfunction extractVariableDefaults(\n hclJson: Record<string, unknown>\n): Record<string, unknown> {\n const defaults: Record<string, unknown> = {};\n\n const variableBlock = hclJson[\"variable\"];\n if (!variableBlock || typeof variableBlock !== \"object\") {\n return defaults;\n }\n\n // Structure: { \"var_name\": [{ default: value, type: \"...\", description: \"...\" }] }\n for (const [varName, declarations] of Object.entries(\n variableBlock as Record<string, unknown>\n )) {\n if (!Array.isArray(declarations) || declarations.length === 0) continue;\n\n const declaration = declarations[0] as Record<string, unknown>;\n if (\"default\" in declaration) {\n defaults[varName] = declaration[\"default\"];\n }\n }\n\n return defaults;\n}\n\n/**\n * Parse a .tfvars file into a key->value map. Supports both simple\n * `key = value` assignments and quoted string values. Lines beginning with\n * `#` are treated as comments and skipped. Multi-line HCL constructs such as\n * heredocs are not supported; only scalar and simple list/map literals that\n * fit on a single line are handled.\n */\nfunction parseTfvars(content: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const rawLine of content.split(\"\\n\")) {\n const line = rawLine.trim();\n\n // Skip blank lines and comments\n if (!line || line.startsWith(\"#\")) continue;\n\n const eqIndex = line.indexOf(\"=\");\n if (eqIndex === -1) continue;\n\n const key = line.slice(0, eqIndex).trim();\n const rawValue = line.slice(eqIndex + 1).trim();\n\n if (!key) continue;\n\n result[key] = parseTfvarsValue(rawValue);\n }\n\n return result;\n}\n\n/**\n * Convert a raw .tfvars value string into the appropriate JS primitive.\n * Handles quoted strings, booleans, null, and numeric literals.\n */\nfunction parseTfvarsValue(raw: string): unknown {\n // Quoted string\n if (\n (raw.startsWith('\"') && raw.endsWith('\"')) ||\n (raw.startsWith(\"'\") && raw.endsWith(\"'\"))\n ) {\n return raw.slice(1, -1);\n }\n\n // Boolean\n if (raw === \"true\") return true;\n if (raw === \"false\") return false;\n\n // Null\n if (raw === \"null\") return null;\n\n // Numeric – try integer first, then float\n if (/^-?\\d+$/.test(raw)) return parseInt(raw, 10);\n if (/^-?\\d+\\.\\d+$/.test(raw)) return parseFloat(raw);\n\n // Unquoted string (e.g. bare region name without quotes in older tfvars)\n return raw;\n}\n\n/**\n * Recursively walk an attribute value tree and replace any `${var.xxx}`\n * interpolation patterns with the resolved variable value. Non-string leaves\n * are passed through unchanged.\n *\n * Terraform's HCL-to-JSON output wraps bare `var.x` references as\n * `\"${var.x}\"` in string contexts. We also handle the case where the entire\n * string is a variable reference and the variable's default is a non-string\n * type (e.g. number), in which case we return the typed value directly.\n */\nexport function substituteVariables(\n value: unknown,\n variables: Record<string, unknown>\n): unknown {\n if (typeof value === \"string\") {\n return substituteInString(value, variables);\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => substituteVariables(item, variables));\n }\n\n if (value !== null && typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n result[k] = substituteVariables(v, variables);\n }\n return result;\n }\n\n return value;\n}\n\nconst VAR_ONLY_RE = /^\\$\\{var\\.([^}]+)\\}$/;\nconst VAR_INLINE_RE = /\\$\\{var\\.([^}]+)\\}/g;\n\nfunction substituteInString(\n str: string,\n variables: Record<string, unknown>\n): unknown {\n // Whole-string variable reference – preserve the original type\n const wholeMatch = VAR_ONLY_RE.exec(str);\n if (wholeMatch) {\n const varName = wholeMatch[1];\n return varName in variables ? variables[varName] : str;\n }\n\n // Inline interpolation – always produces a string result\n return str.replace(VAR_INLINE_RE, (_match, varName: string) => {\n if (varName in variables) {\n const v = variables[varName];\n return v === null ? \"\" : String(v);\n }\n return _match;\n });\n}\n","import type { CloudProvider } from \"../types/index.js\";\n\nconst PROVIDER_PREFIXES: Array<[string, CloudProvider]> = [\n [\"aws_\", \"aws\"],\n [\"azurerm_\", \"azure\"],\n [\"google_\", \"gcp\"],\n];\n\n/**\n * Derive the CloudProvider from a Terraform resource type string by inspecting\n * the well-known provider prefix. Throws when the prefix is not recognised so\n * callers can handle unsupported resource types explicitly.\n */\nexport function detectProvider(resourceType: string): CloudProvider {\n for (const [prefix, provider] of PROVIDER_PREFIXES) {\n if (resourceType.startsWith(prefix)) {\n return provider;\n }\n }\n\n throw new Error(\n `Cannot determine cloud provider for resource type \"${resourceType}\". ` +\n `Supported prefixes: aws_, azurerm_, google_`\n );\n}\n","import type {\n ParsedResource,\n ResourceAttributes,\n CloudProvider,\n} from \"../types/index.js\";\nimport { detectProvider } from \"./provider-detector.js\";\nimport { substituteVariables } from \"./variable-resolver.js\";\nimport { logger } from \"../logger.js\";\n\n// ---------------------------------------------------------------------------\n// Region detection helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Detect the default region for a given provider by inspecting the top-level\n * `provider` block in the parsed HCL JSON. Falls back to a sensible default\n * when no region can be found.\n */\nexport function detectRegionFromProviders(\n hclJson: Record<string, unknown>,\n provider: CloudProvider,\n variables: Record<string, unknown>\n): string {\n const defaults: Record<CloudProvider, string> = {\n aws: \"us-east-1\",\n azure: \"eastus\",\n gcp: \"us-central1\",\n };\n\n const providerBlock = hclJson[\"provider\"];\n if (!providerBlock || typeof providerBlock !== \"object\") {\n return defaults[provider];\n }\n\n const providerKeyMap: Record<CloudProvider, string> = {\n aws: \"aws\",\n azure: \"azurerm\",\n gcp: \"google\",\n };\n\n const key = providerKeyMap[provider];\n const declarations = (providerBlock as Record<string, unknown>)[key];\n if (!Array.isArray(declarations) || declarations.length === 0) {\n return defaults[provider];\n }\n\n const declaration = declarations[0] as Record<string, unknown>;\n\n // Region attribute name varies per provider\n const regionAttr = provider === \"azure\" ? \"location\" : \"region\";\n const rawRegion = declaration[regionAttr];\n if (!rawRegion) return defaults[provider];\n\n const resolved = substituteVariables(rawRegion, variables);\n if (typeof resolved === \"string\" && resolved && !resolved.startsWith(\"${\")) {\n return resolved;\n }\n\n return defaults[provider];\n}\n\n// ---------------------------------------------------------------------------\n// Per-resource-type attribute extraction\n// ---------------------------------------------------------------------------\n\ntype AttributeExtractor = (\n block: Record<string, unknown>\n) => ResourceAttributes;\n\n/**\n * Attempt to read a nested block list and return the first element, or an\n * empty object when the structure is absent.\n */\nfunction firstBlock(\n block: Record<string, unknown>,\n key: string\n): Record<string, unknown> {\n const nested = block[key];\n if (Array.isArray(nested) && nested.length > 0) {\n return nested[0] as Record<string, unknown>;\n }\n return {};\n}\n\nfunction str(v: unknown): string | undefined {\n return typeof v === \"string\" && v ? v : undefined;\n}\n\nfunction num(v: unknown): number | undefined {\n if (typeof v === \"number\") return v;\n if (typeof v === \"string\") {\n const n = Number(v);\n return isNaN(n) ? undefined : n;\n }\n return undefined;\n}\n\nfunction bool(v: unknown): boolean | undefined {\n if (typeof v === \"boolean\") return v;\n if (v === \"true\") return true;\n if (v === \"false\") return false;\n return undefined;\n}\n\nconst extractors: Record<string, AttributeExtractor> = {\n aws_instance(block) {\n const root = firstBlock(block, \"root_block_device\");\n const attrs: ResourceAttributes = {};\n if (str(block[\"instance_type\"])) attrs.instance_type = str(block[\"instance_type\"]);\n if (str(block[\"ami\"])) attrs.ami = str(block[\"ami\"]);\n if (str(block[\"availability_zone\"])) attrs.availability_zone = str(block[\"availability_zone\"]);\n if (root[\"volume_type\"]) attrs.storage_type = str(root[\"volume_type\"]);\n if (root[\"volume_size\"] !== undefined) attrs.storage_size_gb = num(root[\"volume_size\"]);\n if (root[\"iops\"] !== undefined) attrs.iops = num(root[\"iops\"]);\n if (root[\"throughput\"] !== undefined) attrs.throughput_mbps = num(root[\"throughput\"]);\n return attrs;\n },\n\n aws_db_instance(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"instance_class\"])) attrs.instance_type = str(block[\"instance_class\"]);\n if (str(block[\"engine\"])) attrs.engine = str(block[\"engine\"]);\n if (str(block[\"engine_version\"])) attrs.engine_version = str(block[\"engine_version\"]);\n if (str(block[\"storage_type\"])) attrs.storage_type = str(block[\"storage_type\"]);\n if (block[\"allocated_storage\"] !== undefined) attrs.storage_size_gb = num(block[\"allocated_storage\"]);\n if (block[\"iops\"] !== undefined) attrs.iops = num(block[\"iops\"]);\n if (block[\"multi_az\"] !== undefined) attrs.multi_az = bool(block[\"multi_az\"]);\n if (block[\"replicas\"] !== undefined) attrs.replicas = num(block[\"replicas\"]);\n return attrs;\n },\n\n aws_rds_cluster(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"engine\"])) attrs.engine = str(block[\"engine\"]);\n if (str(block[\"engine_version\"])) attrs.engine_version = str(block[\"engine_version\"]);\n if (str(block[\"db_cluster_instance_class\"])) attrs.instance_type = str(block[\"db_cluster_instance_class\"]);\n if (block[\"master_username\"]) attrs.master_username = str(block[\"master_username\"]);\n return attrs;\n },\n\n aws_s3_bucket(block) {\n const attrs: ResourceAttributes = {};\n const lifecycle = firstBlock(block, \"lifecycle_rule\");\n const transition = firstBlock(lifecycle, \"transition\");\n if (str(transition[\"storage_class\"])) attrs.storage_type = str(transition[\"storage_class\"]);\n // Bucket name is useful for cost allocation\n if (str(block[\"bucket\"])) attrs.bucket = str(block[\"bucket\"]);\n return attrs;\n },\n\n aws_lb(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"load_balancer_type\"])) attrs.load_balancer_type = str(block[\"load_balancer_type\"]);\n if (block[\"internal\"] !== undefined) attrs.internal = bool(block[\"internal\"]);\n return attrs;\n },\n\n aws_alb(block) {\n return extractors[\"aws_lb\"](block);\n },\n\n aws_nat_gateway(block) {\n // Presence alone determines cost; record allocation_id for traceability\n const attrs: ResourceAttributes = {};\n if (str(block[\"allocation_id\"])) attrs.allocation_id = str(block[\"allocation_id\"]);\n return attrs;\n },\n\n aws_eks_cluster(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"name\"])) attrs.cluster_name = str(block[\"name\"]);\n return attrs;\n },\n\n aws_eks_node_group(block) {\n const scaling = firstBlock(block, \"scaling_config\");\n const attrs: ResourceAttributes = {};\n const instanceTypes = block[\"instance_types\"];\n if (Array.isArray(instanceTypes) && instanceTypes.length > 0) {\n attrs.instance_type = str(instanceTypes[0]);\n }\n if (scaling[\"desired_size\"] !== undefined) attrs.node_count = num(scaling[\"desired_size\"]);\n if (scaling[\"min_size\"] !== undefined) attrs.min_node_count = num(scaling[\"min_size\"]);\n if (scaling[\"max_size\"] !== undefined) attrs.max_node_count = num(scaling[\"max_size\"]);\n return attrs;\n },\n\n aws_elasticache_cluster(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"node_type\"])) attrs.instance_type = str(block[\"node_type\"]);\n if (str(block[\"engine\"])) attrs.engine = str(block[\"engine\"]);\n if (block[\"num_cache_nodes\"] !== undefined) attrs.node_count = num(block[\"num_cache_nodes\"]);\n return attrs;\n },\n\n aws_elasticache_replication_group(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"node_type\"])) attrs.instance_type = str(block[\"node_type\"]);\n if (block[\"num_cache_clusters\"] !== undefined) attrs.node_count = num(block[\"num_cache_clusters\"]);\n return attrs;\n },\n\n aws_ebs_volume(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"type\"])) attrs.storage_type = str(block[\"type\"]);\n if (block[\"size\"] !== undefined) attrs.storage_size_gb = num(block[\"size\"]);\n if (block[\"iops\"] !== undefined) attrs.iops = num(block[\"iops\"]);\n if (block[\"throughput\"] !== undefined) attrs.throughput_mbps = num(block[\"throughput\"]);\n return attrs;\n },\n\n aws_lambda_function(block) {\n const attrs: ResourceAttributes = {};\n if (block[\"memory_size\"] !== undefined) attrs.memory_size = num(block[\"memory_size\"]);\n if (block[\"timeout\"] !== undefined) attrs.timeout = num(block[\"timeout\"]);\n if (str(block[\"architecture\"])) {\n attrs.architecture = str(block[\"architecture\"]);\n } else {\n // architecture can also be an array in HCL JSON\n const arch = block[\"architectures\"];\n if (Array.isArray(arch) && arch.length > 0) {\n attrs.architecture = str(arch[0]);\n }\n }\n if (str(block[\"runtime\"])) attrs.runtime = str(block[\"runtime\"]);\n return attrs;\n },\n\n aws_dynamodb_table(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"billing_mode\"])) attrs.billing_mode = str(block[\"billing_mode\"]);\n if (block[\"read_capacity\"] !== undefined) attrs.read_capacity = num(block[\"read_capacity\"]);\n if (block[\"write_capacity\"] !== undefined) attrs.write_capacity = num(block[\"write_capacity\"]);\n return attrs;\n },\n\n aws_efs_file_system(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"performance_mode\"])) attrs.performance_mode = str(block[\"performance_mode\"]);\n if (str(block[\"throughput_mode\"])) attrs.throughput_mode = str(block[\"throughput_mode\"]);\n return attrs;\n },\n\n aws_cloudfront_distribution(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"price_class\"])) attrs.price_class = str(block[\"price_class\"]);\n return attrs;\n },\n\n aws_sqs_queue(block) {\n const attrs: ResourceAttributes = {};\n if (block[\"fifo_queue\"] !== undefined) attrs.fifo_queue = bool(block[\"fifo_queue\"]);\n return attrs;\n },\n\n // ---------------------------------------------------------------------------\n // Azure\n // ---------------------------------------------------------------------------\n\n azurerm_virtual_machine(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"vm_size\"])) attrs.vm_size = str(block[\"vm_size\"]);\n if (str(block[\"location\"])) attrs.location = str(block[\"location\"]);\n return attrs;\n },\n\n azurerm_linux_virtual_machine(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"size\"])) attrs.vm_size = str(block[\"size\"]);\n if (str(block[\"location\"])) attrs.location = str(block[\"location\"]);\n return attrs;\n },\n\n azurerm_windows_virtual_machine(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"size\"])) attrs.vm_size = str(block[\"size\"]);\n if (str(block[\"location\"])) attrs.location = str(block[\"location\"]);\n attrs.os = \"Windows\";\n return attrs;\n },\n\n azurerm_managed_disk(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"storage_account_type\"])) attrs.storage_type = str(block[\"storage_account_type\"]);\n if (block[\"disk_size_gb\"] !== undefined) attrs.storage_size_gb = num(block[\"disk_size_gb\"]);\n if (block[\"disk_iops_read_write\"] !== undefined) attrs.iops = num(block[\"disk_iops_read_write\"]);\n if (str(block[\"location\"])) attrs.location = str(block[\"location\"]);\n return attrs;\n },\n\n azurerm_sql_server(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"version\"])) attrs.engine_version = str(block[\"version\"]);\n if (str(block[\"location\"])) attrs.location = str(block[\"location\"]);\n return attrs;\n },\n\n azurerm_mssql_database(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"sku_name\"])) attrs.sku = str(block[\"sku_name\"]);\n if (block[\"max_size_gb\"] !== undefined) attrs.storage_size_gb = num(block[\"max_size_gb\"]);\n return attrs;\n },\n\n azurerm_kubernetes_cluster(block) {\n const defaultPool = firstBlock(block, \"default_node_pool\");\n const attrs: ResourceAttributes = {};\n if (str(defaultPool[\"vm_size\"])) attrs.vm_size = str(defaultPool[\"vm_size\"]);\n if (defaultPool[\"node_count\"] !== undefined) attrs.node_count = num(defaultPool[\"node_count\"]);\n if (defaultPool[\"min_count\"] !== undefined) attrs.min_node_count = num(defaultPool[\"min_count\"]);\n if (defaultPool[\"max_count\"] !== undefined) attrs.max_node_count = num(defaultPool[\"max_count\"]);\n if (str(block[\"location\"])) attrs.location = str(block[\"location\"]);\n return attrs;\n },\n\n azurerm_cosmosdb_account(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"offer_type\"])) attrs.offer_type = str(block[\"offer_type\"]);\n if (str(block[\"kind\"])) attrs.kind = str(block[\"kind\"]);\n // capabilities is an array of blocks with a \"name\" attribute\n const capabilities = block[\"capabilities\"];\n if (Array.isArray(capabilities)) {\n const capNames = capabilities\n .map((c) => (typeof c === \"object\" && c !== null ? str((c as Record<string, unknown>)[\"name\"]) : undefined))\n .filter((n): n is string => n !== undefined);\n if (capNames.length > 0) attrs.capabilities = capNames;\n }\n return attrs;\n },\n\n azurerm_app_service_plan(block) {\n const attrs: ResourceAttributes = {};\n const skuBlock = firstBlock(block, \"sku\");\n if (str(skuBlock[\"tier\"])) attrs.sku_tier = str(skuBlock[\"tier\"]);\n if (str(skuBlock[\"size\"])) attrs.sku_size = str(skuBlock[\"size\"]);\n // newer azurerm provider uses sku_name directly\n if (str(block[\"sku_name\"])) attrs.sku = str(block[\"sku_name\"]);\n return attrs;\n },\n\n azurerm_function_app(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"app_service_plan_id\"])) attrs.app_service_plan_id = str(block[\"app_service_plan_id\"]);\n return attrs;\n },\n\n azurerm_redis_cache(block) {\n const attrs: ResourceAttributes = {};\n if (block[\"capacity\"] !== undefined) attrs.capacity = num(block[\"capacity\"]);\n if (str(block[\"family\"])) attrs.family = str(block[\"family\"]);\n if (str(block[\"sku_name\"])) attrs.sku = str(block[\"sku_name\"]);\n return attrs;\n },\n\n azurerm_cosmosdb_sql_database(block) {\n const attrs: ResourceAttributes = {};\n if (block[\"throughput\"] !== undefined) attrs.throughput = num(block[\"throughput\"]);\n return attrs;\n },\n\n azurerm_storage_account(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"account_tier\"])) attrs.account_tier = str(block[\"account_tier\"]);\n if (str(block[\"account_replication_type\"])) attrs.account_replication_type = str(block[\"account_replication_type\"]);\n return attrs;\n },\n\n // ---------------------------------------------------------------------------\n // GCP\n // ---------------------------------------------------------------------------\n\n google_compute_instance(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"machine_type\"])) attrs.machine_type = str(block[\"machine_type\"]);\n if (str(block[\"zone\"])) attrs.zone = str(block[\"zone\"]);\n const boot = firstBlock(block, \"boot_disk\");\n const initParams = firstBlock(boot, \"initialize_params\");\n if (str(initParams[\"type\"])) attrs.storage_type = str(initParams[\"type\"]);\n if (initParams[\"size\"] !== undefined) attrs.storage_size_gb = num(initParams[\"size\"]);\n return attrs;\n },\n\n google_compute_disk(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"type\"])) attrs.storage_type = str(block[\"type\"]);\n if (block[\"size\"] !== undefined) attrs.storage_size_gb = num(block[\"size\"]);\n if (str(block[\"zone\"])) attrs.zone = str(block[\"zone\"]);\n return attrs;\n },\n\n google_sql_database_instance(block) {\n const settings = firstBlock(block, \"settings\");\n const attrs: ResourceAttributes = {};\n if (str(settings[\"tier\"])) attrs.tier = str(settings[\"tier\"]);\n if (str(block[\"database_version\"])) attrs.engine = str(block[\"database_version\"]);\n if (str(block[\"region\"])) attrs.region_attr = str(block[\"region\"]);\n const dataCacheConfig = firstBlock(settings, \"data_cache_config\");\n if (dataCacheConfig[\"data_cache_enabled\"] !== undefined) {\n attrs.data_cache_enabled = bool(dataCacheConfig[\"data_cache_enabled\"]);\n }\n return attrs;\n },\n\n google_container_cluster(block) {\n const nodeConfig = firstBlock(block, \"node_config\");\n const attrs: ResourceAttributes = {};\n if (str(nodeConfig[\"machine_type\"])) attrs.machine_type = str(nodeConfig[\"machine_type\"]);\n if (block[\"initial_node_count\"] !== undefined) attrs.node_count = num(block[\"initial_node_count\"]);\n if (str(block[\"location\"])) attrs.zone = str(block[\"location\"]);\n return attrs;\n },\n\n google_container_node_pool(block) {\n const nodeConfig = firstBlock(block, \"node_config\");\n const autoscaling = firstBlock(block, \"autoscaling\");\n const attrs: ResourceAttributes = {};\n if (str(nodeConfig[\"machine_type\"])) attrs.machine_type = str(nodeConfig[\"machine_type\"]);\n if (block[\"node_count\"] !== undefined) attrs.node_count = num(block[\"node_count\"]);\n if (autoscaling[\"min_node_count\"] !== undefined) attrs.min_node_count = num(autoscaling[\"min_node_count\"]);\n if (autoscaling[\"max_node_count\"] !== undefined) attrs.max_node_count = num(autoscaling[\"max_node_count\"]);\n return attrs;\n },\n\n google_cloud_run_service(block) {\n const attrs: ResourceAttributes = {};\n const template = firstBlock(block, \"template\");\n const spec = firstBlock(template, \"spec\");\n const container = firstBlock(spec, \"containers\");\n const resources = firstBlock(container, \"resources\");\n const limits = firstBlock(resources, \"limits\");\n if (str(limits[\"cpu\"])) attrs.cpu = str(limits[\"cpu\"]);\n if (str(limits[\"memory\"])) attrs.memory = str(limits[\"memory\"]);\n return attrs;\n },\n\n google_cloudfunctions_function(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"runtime\"])) attrs.runtime = str(block[\"runtime\"]);\n if (block[\"available_memory_mb\"] !== undefined) attrs.memory_size = num(block[\"available_memory_mb\"]);\n return attrs;\n },\n\n google_bigquery_dataset(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"location\"])) attrs.location = str(block[\"location\"]);\n return attrs;\n },\n\n google_redis_instance(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"tier\"])) attrs.tier = str(block[\"tier\"]);\n if (block[\"memory_size_gb\"] !== undefined) attrs.memory_size = num(block[\"memory_size_gb\"]);\n return attrs;\n },\n\n google_artifact_registry_repository(block) {\n const attrs: ResourceAttributes = {};\n if (str(block[\"format\"])) attrs.format = str(block[\"format\"]);\n return attrs;\n },\n};\n\n// ---------------------------------------------------------------------------\n// Region from resource-level attributes\n// ---------------------------------------------------------------------------\n\n/**\n * Some resource types carry their own region/zone/location attribute that can\n * be used as a fallback when no provider block region is available.\n */\nfunction regionFromResourceBlock(\n resourceType: string,\n block: Record<string, unknown>,\n provider: CloudProvider\n): string | undefined {\n switch (provider) {\n case \"azure\": {\n const loc = str(block[\"location\"]);\n return loc && !loc.startsWith(\"${\") ? loc : undefined;\n }\n case \"gcp\": {\n // zone like \"us-central1-a\" -> strip suffix\n const zone = str(block[\"zone\"]);\n if (zone && !zone.startsWith(\"${\")) {\n const parts = zone.split(\"-\");\n return parts.length > 2 ? parts.slice(0, -1).join(\"-\") : zone;\n }\n return str(block[\"region\"]);\n }\n case \"aws\": {\n const az = str(block[\"availability_zone\"]);\n if (az && !az.startsWith(\"${\")) {\n const parts = az.split(\"-\");\n return parts.length > 2 ? parts.slice(0, -1).join(\"-\") : az;\n }\n return undefined;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Tag extraction\n// ---------------------------------------------------------------------------\n\nfunction extractTags(block: Record<string, unknown>): Record<string, string> {\n const tags = block[\"tags\"];\n if (!tags || typeof tags !== \"object\" || Array.isArray(tags)) return {};\n\n const result: Record<string, string> = {};\n for (const [k, v] of Object.entries(tags as Record<string, unknown>)) {\n if (typeof v === \"string\") result[k] = v;\n else if (v !== null && v !== undefined) result[k] = String(v);\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// count / for_each expansion helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a `count` attribute to a concrete integer. Returns the count and\n * pushes a warning into the provided array when the value cannot be resolved.\n */\nfunction resolveCount(\n rawCount: unknown,\n resourceId: string,\n warnings: string[]\n): number {\n const n = num(rawCount);\n if (n !== undefined && Number.isInteger(n) && n >= 0) return n;\n\n // Could be a variable reference or expression that wasn't resolved\n warnings.push(\n `Resource \"${resourceId}\" has a count that could not be resolved to a number. Defaulting to 1.`\n );\n return 1;\n}\n\n/**\n * Resolve a `for_each` attribute to an array of keys. When the value is an\n * object, the object's keys are used. When it is an array, each element\n * (coerced to string) becomes a key. When neither can be determined a warning\n * is pushed and a single-element array `[\"0\"]` is returned (equivalent to\n * count = 1).\n */\nfunction resolveForEachKeys(\n rawForEach: unknown,\n resourceId: string,\n warnings: string[]\n): string[] {\n if (rawForEach && typeof rawForEach === \"object\" && !Array.isArray(rawForEach)) {\n const keys = Object.keys(rawForEach as Record<string, unknown>);\n if (keys.length > 0) return keys;\n }\n\n if (Array.isArray(rawForEach) && rawForEach.length > 0) {\n return rawForEach.map((v, i) =>\n typeof v === \"string\" ? v : typeof v === \"number\" ? String(v) : String(i)\n );\n }\n\n // Unresolvable (e.g. still a variable reference string)\n warnings.push(\n `Resource \"${resourceId}\" has a for_each that could not be resolved. Defaulting to 1 instance.`\n );\n return [\"0\"];\n}\n\n// ---------------------------------------------------------------------------\n// Main extractor\n// ---------------------------------------------------------------------------\n\n/**\n * Walk the `resource` map in parsed HCL JSON and produce a flat array of\n * ParsedResource objects. Variable substitution is applied to all attribute\n * values before extraction so that downstream consumers always see resolved\n * strings/numbers wherever possible.\n *\n * count and for_each meta-arguments are expanded into multiple resources.\n * Data source blocks are silently skipped. Module blocks generate informational\n * warnings without being expanded.\n */\nexport function extractResources(\n hclJson: Record<string, unknown>,\n variables: Record<string, unknown>,\n sourceFile: string,\n defaultRegions: Partial<Record<CloudProvider, string>> = {},\n warnings: string[] = []\n): ParsedResource[] {\n const resources: ParsedResource[] = [];\n\n // Task 2: Detect module blocks and emit warnings\n const moduleBlock = hclJson[\"module\"];\n if (moduleBlock && typeof moduleBlock === \"object\" && !Array.isArray(moduleBlock)) {\n for (const moduleName of Object.keys(moduleBlock as Record<string, unknown>)) {\n warnings.push(\n `Module \"${moduleName}\" detected but not expanded. Resources inside modules are not included in the estimate.`\n );\n logger.debug(\"Module detected, skipping expansion\", { moduleName });\n }\n }\n\n const resourceBlock = hclJson[\"resource\"];\n\n if (!resourceBlock || typeof resourceBlock !== \"object\") {\n return resources;\n }\n\n for (const [resourceType, instances] of Object.entries(\n resourceBlock as Record<string, unknown>\n )) {\n let provider: CloudProvider;\n try {\n provider = detectProvider(resourceType);\n } catch {\n logger.warn(\"Skipping resource with unknown provider prefix\", {\n resourceType,\n });\n continue;\n }\n\n if (!instances || typeof instances !== \"object\" || Array.isArray(instances)) {\n continue;\n }\n\n for (const [resourceName, blockList] of Object.entries(\n instances as Record<string, unknown>\n )) {\n if (!Array.isArray(blockList) || blockList.length === 0) continue;\n\n const rawBlock = blockList[0] as Record<string, unknown>;\n // Substitute variables throughout the entire block before extraction\n const block = substituteVariables(rawBlock, variables) as Record<\n string,\n unknown\n >;\n\n // Determine region: resource-level > provider default > hard default\n const resourceRegion = regionFromResourceBlock(resourceType, block, provider);\n const region =\n resourceRegion ??\n defaultRegions[provider] ??\n (provider === \"aws\"\n ? \"us-east-1\"\n : provider === \"azure\"\n ? \"eastus\"\n : \"us-central1\");\n\n // Extract cost-relevant attributes using per-type extractor or generic\n const extractor = extractors[resourceType];\n const attributes: ResourceAttributes = extractor\n ? extractor(block)\n : {};\n\n const tags = extractTags(block);\n const baseId = `${resourceType}.${resourceName}`;\n\n // ------------------------------------------------------------------\n // Expand count / for_each\n // ------------------------------------------------------------------\n\n const rawCount = block[\"count\"];\n const rawForEach = block[\"for_each\"];\n\n if (rawCount !== undefined) {\n // count expansion\n const count = resolveCount(rawCount, baseId, warnings);\n for (let i = 0; i < count; i++) {\n resources.push({\n id: `${baseId}[${i}]`,\n type: resourceType,\n name: resourceName,\n provider,\n region,\n attributes,\n tags,\n source_file: sourceFile,\n });\n }\n } else if (rawForEach !== undefined) {\n // for_each expansion\n const keys = resolveForEachKeys(rawForEach, baseId, warnings);\n for (const key of keys) {\n resources.push({\n id: `${baseId}[\"${key}\"]`,\n type: resourceType,\n name: resourceName,\n provider,\n region,\n attributes,\n tags,\n source_file: sourceFile,\n });\n }\n } else {\n // No expansion – single resource\n resources.push({\n id: baseId,\n type: resourceType,\n name: resourceName,\n provider,\n region,\n attributes,\n tags,\n source_file: sourceFile,\n });\n }\n\n logger.debug(\"Extracted resource\", {\n id: baseId,\n region,\n provider,\n });\n }\n }\n\n return resources;\n}\n","import type { CloudProvider, ResourceInventory, ParsedResource } from \"../types/index.js\";\nimport { parseHclToJson } from \"./hcl-parser.js\";\nimport { resolveVariables } from \"./variable-resolver.js\";\nimport {\n extractResources,\n detectRegionFromProviders,\n} from \"./resource-extractor.js\";\nimport { detectProvider } from \"./provider-detector.js\";\nimport { logger } from \"../logger.js\";\n\nexport { parseHclToJson } from \"./hcl-parser.js\";\nexport { detectProvider } from \"./provider-detector.js\";\nexport { resolveVariables, substituteVariables } from \"./variable-resolver.js\";\nexport { extractResources, detectRegionFromProviders } from \"./resource-extractor.js\";\n\n// ---------------------------------------------------------------------------\n// Provider + region inference\n// ---------------------------------------------------------------------------\n\nconst PROVIDER_DEFAULTS: Record<CloudProvider, string> = {\n aws: \"us-east-1\",\n azure: \"eastus\",\n gcp: \"us-central1\",\n};\n\n/**\n * Heuristically determine the primary provider from a set of parsed resources.\n * Returns the provider that appears most often, falling back to \"aws\" when the\n * set is empty or tied.\n */\nfunction inferDominantProvider(resources: ParsedResource[]): CloudProvider {\n if (resources.length === 0) return \"aws\";\n\n const counts: Partial<Record<CloudProvider, number>> = {};\n for (const r of resources) {\n counts[r.provider] = (counts[r.provider] ?? 0) + 1;\n }\n\n let dominant: CloudProvider = \"aws\";\n let max = 0;\n for (const [p, c] of Object.entries(counts) as [CloudProvider, number][]) {\n if (c > max) {\n max = c;\n dominant = p;\n }\n }\n return dominant;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Parse one or more Terraform HCL files (and an optional .tfvars override\n * string) into a unified ResourceInventory.\n *\n * Processing steps:\n * 1. Parse each HCL file to JSON in parallel.\n * 2. Merge all parsed JSON objects to build a combined view of variables and\n * provider blocks.\n * 3. Resolve variables (defaults + tfvars overrides).\n * 4. Detect the default region for each cloud provider from provider blocks.\n * 5. Extract resources from every file, applying the resolved variables.\n * 6. Build and return the ResourceInventory.\n */\nexport async function parseTerraform(\n files: { path: string; content: string }[],\n tfvarsContent?: string\n): Promise<ResourceInventory> {\n const warnings: string[] = [];\n const parsedJsons: Array<{ path: string; json: Record<string, unknown> }> =\n [];\n\n // Step 1: Parse all files\n for (const file of files) {\n try {\n const json = await parseHclToJson(file.content, file.path);\n parsedJsons.push({ path: file.path, json });\n } catch (err) {\n const msg =\n err instanceof Error ? err.message : String(err);\n warnings.push(`Parse error in ${file.path}: ${msg}`);\n logger.warn(\"Skipping file due to parse error\", {\n path: file.path,\n error: msg,\n });\n }\n }\n\n if (parsedJsons.length === 0) {\n logger.warn(\"No files were successfully parsed\");\n return {\n provider: \"aws\",\n region: PROVIDER_DEFAULTS[\"aws\"],\n resources: [],\n total_count: 0,\n by_type: {},\n parse_warnings: warnings,\n };\n }\n\n // Step 2: Merge all parsed JSONs into a single combined object for variable\n // and provider block resolution. Resources are extracted per-file below.\n const combined = mergeHclJsons(parsedJsons.map((p) => p.json));\n\n // Step 3: Resolve variables\n const variables = resolveVariables(combined, tfvarsContent);\n\n // Step 4: Detect region per provider from merged provider blocks\n const providers: CloudProvider[] = [\"aws\", \"azure\", \"gcp\"];\n const defaultRegions: Partial<Record<CloudProvider, string>> = {};\n for (const p of providers) {\n defaultRegions[p] = detectRegionFromProviders(combined, p, variables);\n }\n\n // Step 5: Extract resources from each file\n const allResources: ParsedResource[] = [];\n for (const { path, json } of parsedJsons) {\n try {\n const resources = extractResources(json, variables, path, defaultRegions, warnings);\n allResources.push(...resources);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n warnings.push(`Extraction error in ${path}: ${msg}`);\n logger.warn(\"Resource extraction failed\", { path, error: msg });\n }\n }\n\n // Step 6: Build inventory\n const dominantProvider = inferDominantProvider(allResources);\n const dominantRegion =\n defaultRegions[dominantProvider] ?? PROVIDER_DEFAULTS[dominantProvider];\n\n const byType: Record<string, number> = {};\n for (const r of allResources) {\n byType[r.type] = (byType[r.type] ?? 0) + 1;\n }\n\n const inventory: ResourceInventory = {\n provider: dominantProvider,\n region: dominantRegion,\n resources: allResources,\n total_count: allResources.length,\n by_type: byType,\n parse_warnings: warnings,\n };\n\n logger.info(\"Terraform parse complete\", {\n fileCount: files.length,\n resourceCount: allResources.length,\n provider: dominantProvider,\n region: dominantRegion,\n warningCount: warnings.length,\n });\n\n return inventory;\n}\n\n// ---------------------------------------------------------------------------\n// Merge helper\n// ---------------------------------------------------------------------------\n\n/**\n * Shallow-merge multiple HCL JSON objects so that variable and provider block\n * information from separate files (e.g. variables.tf and main.tf) is visible\n * in one place during resolution. Block-level arrays are concatenated rather\n * than overwritten, and the `resource` section is merged at the type level.\n */\nfunction mergeHclJsons(\n jsons: Record<string, unknown>[]\n): Record<string, unknown> {\n const merged: Record<string, unknown> = {};\n\n for (const json of jsons) {\n for (const [key, value] of Object.entries(json)) {\n if (!(key in merged)) {\n merged[key] = deepClone(value);\n continue;\n }\n\n const existing = merged[key];\n\n if (\n value !== null &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n existing !== null &&\n typeof existing === \"object\" &&\n !Array.isArray(existing)\n ) {\n // Recursively merge objects (handles provider, resource, variable blocks)\n merged[key] = mergeObjects(\n existing as Record<string, unknown>,\n value as Record<string, unknown>\n );\n } else if (Array.isArray(existing) && Array.isArray(value)) {\n merged[key] = [...existing, ...value];\n } else {\n // Scalar or incompatible types: last-writer wins\n merged[key] = deepClone(value);\n }\n }\n }\n\n return merged;\n}\n\nfunction mergeObjects(\n a: Record<string, unknown>,\n b: Record<string, unknown>\n): Record<string, unknown> {\n const result = { ...a };\n for (const [key, bVal] of Object.entries(b)) {\n const aVal = result[key];\n if (\n aVal !== null &&\n typeof aVal === \"object\" &&\n !Array.isArray(aVal) &&\n bVal !== null &&\n typeof bVal === \"object\" &&\n !Array.isArray(bVal)\n ) {\n result[key] = mergeObjects(\n aVal as Record<string, unknown>,\n bVal as Record<string, unknown>\n );\n } else if (Array.isArray(aVal) && Array.isArray(bVal)) {\n result[key] = [...aVal, ...bVal];\n } else {\n result[key] = deepClone(bVal);\n }\n }\n return result;\n}\n\nfunction deepClone(value: unknown): unknown {\n if (value === null || typeof value !== \"object\") return value;\n return JSON.parse(JSON.stringify(value));\n}\n","import { z } from \"zod\";\nimport type { CloudProvider } from \"../types/resources.js\";\nimport type { CloudCostConfig } from \"../types/config.js\";\nimport type { PricingEngine } from \"../pricing/pricing-engine.js\";\nimport { parseTerraform } from \"../parsers/index.js\";\nimport { mapRegion } from \"../mapping/region-mapper.js\";\nimport { CostEngine } from \"../calculator/cost-engine.js\";\n\n// ---------------------------------------------------------------------------\n// Schema\n// ---------------------------------------------------------------------------\n\nexport const estimateCostSchema = z.object({\n files: z.array(\n z.object({\n path: z.string().describe(\"File path\"),\n content: z.string().describe(\"File content (HCL)\"),\n })\n ),\n tfvars: z.string().optional().describe(\"Contents of terraform.tfvars file\"),\n provider: z\n .enum([\"aws\", \"azure\", \"gcp\"])\n .describe(\"Target cloud provider to estimate costs for\"),\n region: z\n .string()\n .optional()\n .describe(\n \"Target region for pricing lookup. Defaults to the source region mapped to the target provider.\"\n ),\n});\n\n// ---------------------------------------------------------------------------\n// Handler\n// ---------------------------------------------------------------------------\n\n/**\n * Parse the supplied Terraform files, map resources to the target provider,\n * and return a full CostBreakdown for that provider.\n */\nexport async function estimateCost(\n params: z.infer<typeof estimateCostSchema>,\n pricingEngine: PricingEngine,\n config: CloudCostConfig\n): Promise<object> {\n const inventory = await parseTerraform(params.files, params.tfvars);\n\n const targetProvider = params.provider as CloudProvider;\n\n // Resolve the target region: use the explicit override if supplied,\n // otherwise map the source region to the nearest equivalent on the target\n // provider.\n const targetRegion =\n params.region ??\n mapRegion(inventory.region, inventory.provider, targetProvider);\n\n const costEngine = new CostEngine(pricingEngine, config);\n const breakdown = await costEngine.calculateBreakdown(\n inventory.resources,\n targetProvider,\n targetRegion\n );\n\n // Surface parse warnings alongside the cost breakdown so callers have a\n // complete picture of data quality for this estimate.\n const parseWarnings = inventory.parse_warnings ?? [];\n const allWarnings = [...new Set([...parseWarnings, ...(breakdown.warnings ?? [])])];\n\n return {\n ...breakdown,\n parse_warnings: parseWarnings,\n warnings: allWarnings,\n } as unknown as object;\n}\n","import type { CloudProvider } from \"../types/resources.js\";\nimport type { RegionMapping } from \"../types/mapping.js\";\nimport { getRegionMappings } from \"../data/loader.js\";\nimport { logger } from \"../logger.js\";\n\n// Default regions to fall back to when a mapping does not exist.\nconst DEFAULT_REGIONS: Record<CloudProvider, string> = {\n aws: \"us-east-1\",\n azure: \"eastus\",\n gcp: \"us-central1\",\n};\n\n/**\n * Maps a region identifier from one cloud provider to the geographically\n * closest equivalent on a target provider.\n *\n * Falls back to the canonical default region for the target provider when the\n * source region is not present in the mapping table. The fallback is logged at\n * debug level so callers can diagnose unexpected mappings in tests.\n */\nexport function mapRegion(\n region: string,\n sourceProvider: CloudProvider,\n targetProvider: CloudProvider\n): string {\n if (sourceProvider === targetProvider) return region;\n\n const mappings = getRegionMappings();\n\n const row = mappings.find(\n (entry: RegionMapping) => entry[sourceProvider] === region\n );\n\n if (!row) {\n const fallback = DEFAULT_REGIONS[targetProvider];\n logger.debug(\"region-mapper: no mapping found, using default\", {\n region,\n sourceProvider,\n targetProvider,\n fallback,\n });\n return fallback;\n }\n\n const mapped = row[targetProvider];\n if (!mapped) {\n return DEFAULT_REGIONS[targetProvider];\n }\n\n return mapped;\n}\n","import type { CloudProvider, InstanceSpec } from \"../types/resources.js\";\nimport {\n getInstanceMap,\n getAwsInstances,\n getAzureVmSizes,\n getGcpMachineTypes,\n} from \"../data/loader.js\";\nimport { logger } from \"../logger.js\";\n\n// ---------------------------------------------------------------------------\n// Directional key builder\n// ---------------------------------------------------------------------------\n\ntype DirectionKey =\n | \"aws_to_azure\"\n | \"aws_to_gcp\"\n | \"azure_to_aws\"\n | \"azure_to_gcp\"\n | \"gcp_to_aws\"\n | \"gcp_to_azure\";\n\nfunction directionKey(\n source: CloudProvider,\n target: CloudProvider\n): DirectionKey | null {\n if (source === target) return null;\n return `${source}_to_${target}` as DirectionKey;\n}\n\n// ---------------------------------------------------------------------------\n// Spec loaders per provider\n// ---------------------------------------------------------------------------\n\nfunction getSpecsForProvider(provider: CloudProvider): InstanceSpec[] {\n switch (provider) {\n case \"aws\":\n return getAwsInstances();\n case \"azure\":\n return getAzureVmSizes();\n case \"gcp\":\n return getGcpMachineTypes();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Scoring constants\n// ---------------------------------------------------------------------------\n\nconst SCORE_EXACT_VCPU = 40;\nconst SCORE_APPROX_VCPU = 20;\nconst SCORE_EXACT_MEMORY = 40;\nconst SCORE_APPROX_MEMORY = 20;\nconst SCORE_CATEGORY = 20;\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Maps an instance type from one cloud provider to the closest equivalent on\n * another provider.\n *\n * Strategy:\n * 1. Exact lookup in the pre-computed directional mapping table.\n * 2. Spec-based nearest-instance fallback if no direct mapping exists.\n *\n * Returns null when neither strategy produces a result (e.g. an unsupported\n * instance type with no data file entry).\n */\nexport function mapInstance(\n instanceType: string,\n sourceProvider: CloudProvider,\n targetProvider: CloudProvider\n): string | null {\n if (sourceProvider === targetProvider) return instanceType;\n\n const key = directionKey(sourceProvider, targetProvider);\n if (!key) return instanceType;\n\n // Step 1: exact lookup in the pre-computed table.\n const instanceMap = getInstanceMap();\n const directionalMap = instanceMap[key] as Record<string, string> | undefined;\n\n if (directionalMap) {\n const exact = directionalMap[instanceType];\n if (exact) {\n logger.debug(\"instance-mapper: exact match\", {\n instanceType,\n sourceProvider,\n targetProvider,\n result: exact,\n });\n return exact;\n }\n }\n\n // Step 2: spec-based fallback.\n const sourceSpecs = getSpecsForProvider(sourceProvider);\n const sourceSpec = sourceSpecs.find(\n (s) => s.instance_type === instanceType\n );\n\n if (!sourceSpec) {\n logger.debug(\"instance-mapper: source spec not found, cannot map\", {\n instanceType,\n sourceProvider,\n });\n return null;\n }\n\n return findNearestInstance(\n {\n vcpus: sourceSpec.vcpus,\n memory_gb: sourceSpec.memory_gb,\n category: sourceSpec.category,\n },\n targetProvider\n );\n}\n\n/**\n * Finds the closest matching instance type on a target provider given a set\n * of hardware specifications.\n *\n * Scoring rubric (higher is better):\n * Exact vCPU match: 40 pts\n * Closest vCPU: up to 20 pts (scaled by 1 / relative_distance)\n * Exact memory match: 40 pts\n * Closest memory: up to 20 pts (scaled by 1 / relative_distance)\n * Same category: 20 pts\n */\nexport function findNearestInstance(\n spec: { vcpus: number; memory_gb: number; category: string },\n targetProvider: CloudProvider\n): string | null {\n const candidates = getSpecsForProvider(targetProvider);\n\n if (candidates.length === 0) return null;\n\n let bestScore = -1;\n let bestType: string | null = null;\n\n for (const candidate of candidates) {\n let score = 0;\n\n // vCPU scoring\n if (candidate.vcpus === spec.vcpus) {\n score += SCORE_EXACT_VCPU;\n } else {\n // Scaled proximity score: full points when ratio = 1, decays as it diverges.\n const larger = Math.max(candidate.vcpus, spec.vcpus);\n const smaller = Math.min(candidate.vcpus, spec.vcpus);\n if (smaller > 0) {\n score += SCORE_APPROX_VCPU * (smaller / larger);\n }\n }\n\n // Memory scoring\n if (candidate.memory_gb === spec.memory_gb) {\n score += SCORE_EXACT_MEMORY;\n } else {\n const larger = Math.max(candidate.memory_gb, spec.memory_gb);\n const smaller = Math.min(candidate.memory_gb, spec.memory_gb);\n if (smaller > 0) {\n score += SCORE_APPROX_MEMORY * (smaller / larger);\n }\n }\n\n // Category bonus\n if (candidate.category === spec.category) {\n score += SCORE_CATEGORY;\n }\n\n if (score > bestScore) {\n bestScore = score;\n bestType = candidate.instance_type;\n }\n }\n\n if (bestType) {\n logger.debug(\"instance-mapper: nearest match found\", {\n spec,\n targetProvider,\n result: bestType,\n score: bestScore,\n });\n }\n\n return bestType;\n}\n","import type { CloudProvider } from \"../types/resources.js\";\nimport { getStorageMap } from \"../data/loader.js\";\nimport { logger } from \"../logger.js\";\n\n/**\n * Maps a storage type identifier from one cloud provider to the equivalent on\n * a target provider.\n *\n * Both block_storage and object_storage sections of the mapping table are\n * checked. Returns null when no match is found.\n */\nexport function mapStorageType(\n storageType: string,\n sourceProvider: CloudProvider,\n targetProvider: CloudProvider\n): string | null {\n if (sourceProvider === targetProvider) return storageType;\n\n const { block_storage, object_storage } = getStorageMap();\n\n // Search block storage first, then object storage.\n const allEntries = [...block_storage, ...object_storage];\n\n const row = allEntries.find(\n (entry) => entry[sourceProvider] === storageType\n );\n\n if (!row) {\n logger.debug(\"storage-mapper: no mapping found\", {\n storageType,\n sourceProvider,\n targetProvider,\n });\n return null;\n }\n\n const mapped = row[targetProvider];\n if (!mapped) {\n logger.debug(\"storage-mapper: target column missing in row\", {\n storageType,\n sourceProvider,\n targetProvider,\n });\n return null;\n }\n\n return mapped;\n}\n","import type { ParsedResource } from \"../types/resources.js\";\nimport type { CloudProvider } from \"../types/resources.js\";\nimport type { CostEstimate, CostLineItem } from \"../types/pricing.js\";\nimport type { PricingEngine } from \"../pricing/pricing-engine.js\";\nimport { mapInstance } from \"../mapping/instance-mapper.js\";\nimport { mapStorageType } from \"../mapping/storage-mapper.js\";\nimport { logger } from \"../logger.js\";\n\n/**\n * Calculates the monthly compute cost for a VM-style resource on a target\n * provider.\n *\n * The function:\n * 1. Resolves the target instance type via exact or nearest-match mapping.\n * 2. Fetches the hourly on-demand price from the pricing engine.\n * 3. Adds optional root block device (EBS/disk) storage cost when present.\n * 4. Returns a CostEstimate whose confidence reflects whether the instance\n * mapping was exact (\"high\") or approximate (\"medium\").\n */\nexport async function calculateComputeCost(\n resource: ParsedResource,\n targetProvider: CloudProvider,\n targetRegion: string,\n pricingEngine: PricingEngine,\n monthlyHours: number = 730\n): Promise<CostEstimate> {\n const notes: string[] = [];\n const breakdown: CostLineItem[] = [];\n\n // Determine source instance type attribute regardless of provider.\n const sourceInstanceType =\n (resource.attributes.instance_type as string | undefined) ??\n (resource.attributes.vm_size as string | undefined) ??\n (resource.attributes.machine_type as string | undefined) ??\n \"\";\n\n // Map instance type to target provider.\n const mappedInstance = sourceInstanceType\n ? mapInstance(sourceInstanceType, resource.provider, targetProvider)\n : null;\n\n let confidence: \"high\" | \"medium\" | \"low\" = \"low\";\n let specBasedMapping = false;\n\n if (!mappedInstance) {\n notes.push(\n `No instance mapping found for ${sourceInstanceType} (${resource.provider} -> ${targetProvider})`\n );\n } else {\n // Check whether the mapping came from the direct table or was approximate.\n // We infer this by checking if the instance map contains an exact entry;\n // the mapper itself returns null for both \"not found\" and \"spec-fallback\"\n // scenarios without exposing which path was taken. We approximate by\n // looking at whether instance names are literally the same shape.\n const { getInstanceMap } = await import(\"../data/loader.js\");\n const im = getInstanceMap();\n const dirKey = `${resource.provider}_to_${targetProvider}` as keyof typeof im;\n const directMap = im[dirKey] as Record<string, string> | undefined;\n const isExact = directMap?.[sourceInstanceType] === mappedInstance;\n confidence = isExact ? \"high\" : \"medium\";\n\n if (!isExact) {\n specBasedMapping = true;\n notes.push(\n `Instance mapping for ${sourceInstanceType} -> ${mappedInstance} is an approximate spec-based match`\n );\n }\n }\n\n const effectiveInstance = mappedInstance ?? sourceInstanceType;\n\n // Fetch compute price.\n const computePrice = effectiveInstance\n ? await pricingEngine\n .getProvider(targetProvider)\n .getComputePrice(effectiveInstance, targetRegion, resource.attributes.os as string | undefined)\n : null;\n\n let computeMonthlyCost = 0;\n let pricingSource: \"live\" | \"fallback\" | \"bundled\" = \"fallback\";\n\n if (computePrice) {\n const rawSource = computePrice.attributes?.pricing_source;\n if (rawSource === \"bundled\") {\n pricingSource = \"bundled\";\n } else if (rawSource === \"fallback\") {\n pricingSource = \"fallback\";\n notes.push(`Pricing for ${effectiveInstance} uses bundled fallback data (live API unavailable)`);\n } else {\n pricingSource = \"live\";\n }\n\n if (specBasedMapping) {\n notes.push(`Spec-based instance mapping used: ${sourceInstanceType} -> ${mappedInstance}`);\n }\n\n const hourlyPrice = computePrice.price_per_unit;\n computeMonthlyCost = hourlyPrice * monthlyHours;\n\n breakdown.push({\n description: `${effectiveInstance} compute (${monthlyHours}h/month)`,\n unit: \"Hrs\",\n quantity: monthlyHours,\n unit_price: hourlyPrice,\n monthly_cost: computeMonthlyCost,\n });\n } else {\n notes.push(`No pricing data found for ${resource.type} in ${targetRegion}`);\n confidence = \"low\";\n pricingSource = \"fallback\";\n }\n\n // Add root block device / disk storage cost if specified.\n let storageMonthlyCost = 0;\n const rootDisk = resource.attributes.root_block_device as\n | { volume_type?: string; volume_size?: number }\n | undefined;\n const storageType =\n (rootDisk?.volume_type as string | undefined) ??\n (resource.attributes.storage_type as string | undefined);\n const storageSizeGb =\n (rootDisk?.volume_size as number | undefined) ??\n (resource.attributes.storage_size_gb as number | undefined);\n\n if (storageType && storageSizeGb && storageSizeGb > 0) {\n const mappedStorageType = mapStorageType(\n storageType,\n resource.provider,\n targetProvider\n ) ?? storageType;\n\n const storagePrice = await pricingEngine\n .getProvider(targetProvider)\n .getStoragePrice(mappedStorageType, targetRegion, storageSizeGb);\n\n if (storagePrice) {\n storageMonthlyCost = storagePrice.price_per_unit * storageSizeGb;\n breakdown.push({\n description: `Root disk ${mappedStorageType} (${storageSizeGb} GB)`,\n unit: \"GB-Mo\",\n quantity: storageSizeGb,\n unit_price: storagePrice.price_per_unit,\n monthly_cost: storageMonthlyCost,\n });\n } else {\n logger.debug(\"calculateComputeCost: no storage price found\", {\n mappedStorageType,\n targetRegion,\n });\n }\n }\n\n const totalMonthly = computeMonthlyCost + storageMonthlyCost;\n\n return {\n resource_id: resource.id,\n resource_type: resource.type,\n resource_name: resource.name,\n provider: targetProvider,\n region: targetRegion,\n monthly_cost: totalMonthly,\n yearly_cost: totalMonthly * 12,\n currency: \"USD\",\n breakdown,\n confidence,\n notes,\n pricing_source: pricingSource,\n };\n}\n","import type { ParsedResource } from \"../types/resources.js\";\nimport type { CloudProvider } from \"../types/resources.js\";\nimport type { CostEstimate, CostLineItem } from \"../types/pricing.js\";\nimport type { PricingEngine } from \"../pricing/pricing-engine.js\";\nimport { mapInstance } from \"../mapping/instance-mapper.js\";\nimport { logger } from \"../logger.js\";\n\n// AWS RDS instance classes use the \"db.\" prefix. For spec-based mapping to\n// Azure/GCP we strip the prefix, find the nearest compute equivalent, and\n// then translate back to a DB tier identifier.\nfunction normalizeDbInstanceClass(instanceClass: string): string {\n return instanceClass.startsWith(\"db.\") ? instanceClass.slice(3) : instanceClass;\n}\n\n/**\n * Calculates the monthly cost for a managed database instance on a target\n * provider.\n *\n * Handles:\n * - AWS RDS (db.* instance classes)\n * - Azure Flexible Server / SQL MI tiers\n * - GCP Cloud SQL (db-custom-* tiers)\n * - Multi-AZ: doubles the instance cost for AWS, uses ha_multiplier for GCP\n * - Allocated storage pricing\n */\nexport async function calculateDatabaseCost(\n resource: ParsedResource,\n targetProvider: CloudProvider,\n targetRegion: string,\n pricingEngine: PricingEngine,\n monthlyHours: number = 730\n): Promise<CostEstimate> {\n const notes: string[] = [];\n const breakdown: CostLineItem[] = [];\n\n // Resolve source DB instance class across provider attribute conventions.\n const sourceInstanceClass =\n (resource.attributes.instance_class as string | undefined) ??\n (resource.attributes.instance_type as string | undefined) ??\n (resource.attributes.vm_size as string | undefined) ??\n (resource.attributes.tier as string | undefined) ??\n \"\";\n\n const isMultiAz = Boolean(resource.attributes.multi_az);\n const allocatedStorageGb =\n (resource.attributes.allocated_storage as number | undefined) ??\n (resource.attributes.storage_size_gb as number | undefined) ??\n 0;\n const engine =\n (resource.attributes.engine as string | undefined) ?? \"MySQL\";\n\n // Map instance class to target provider equivalent.\n // Strip the \"db.\" prefix for AWS classes before feeding into the generic\n // instance mapper, then try to map back with the db. prefix for the target.\n const normalised = normalizeDbInstanceClass(sourceInstanceClass);\n\n let mappedInstance: string | null = null;\n\n if (targetProvider === \"gcp\") {\n // GCP uses db-custom-* naming; try direct map first, then find nearest.\n mappedInstance = mapInstance(sourceInstanceClass, resource.provider, \"gcp\");\n if (!mappedInstance) {\n // Try stripping db. prefix and mapping from normalized class.\n mappedInstance = mapInstance(normalised, resource.provider, \"gcp\");\n }\n // Prefer a db-custom-* type for GCP databases.\n if (mappedInstance && !mappedInstance.startsWith(\"db-\")) {\n // If we got a compute machine type, try to find the db equivalent.\n const dbMapped = mapInstance(sourceInstanceClass, resource.provider, \"gcp\");\n if (dbMapped) mappedInstance = dbMapped;\n }\n } else if (targetProvider === \"aws\") {\n // Ensure the result has the db. prefix for RDS.\n mappedInstance = mapInstance(sourceInstanceClass, resource.provider, \"aws\");\n if (!mappedInstance && normalised !== sourceInstanceClass) {\n mappedInstance = mapInstance(normalised, resource.provider, \"aws\");\n }\n if (mappedInstance && !mappedInstance.startsWith(\"db.\")) {\n mappedInstance = `db.${mappedInstance}`;\n }\n } else {\n // Azure: use the instance mapper directly.\n mappedInstance = mapInstance(sourceInstanceClass, resource.provider, targetProvider);\n if (!mappedInstance) {\n mappedInstance = mapInstance(normalised, resource.provider, targetProvider);\n }\n }\n\n const effectiveInstance = mappedInstance ?? sourceInstanceClass;\n\n if (!mappedInstance) {\n notes.push(\n `No DB instance mapping found for ${sourceInstanceClass} (${resource.provider} -> ${targetProvider}); using source class`\n );\n }\n\n // Fetch DB price.\n const dbPrice = await pricingEngine\n .getProvider(targetProvider)\n .getDatabasePrice(effectiveInstance, targetRegion, engine);\n\n let instanceMonthlyCost = 0;\n let pricingSource: \"live\" | \"fallback\" | \"bundled\" = \"fallback\";\n\n if (dbPrice) {\n const rawSource = dbPrice.attributes?.pricing_source;\n if (rawSource === \"bundled\") {\n pricingSource = \"bundled\";\n } else if (rawSource === \"fallback\") {\n pricingSource = \"fallback\";\n notes.push(`Pricing for ${effectiveInstance} uses bundled fallback data (live API unavailable)`);\n } else {\n pricingSource = \"live\";\n }\n\n instanceMonthlyCost = dbPrice.price_per_unit * monthlyHours;\n\n // For GCP, apply the HA multiplier from the pricing data when multi-AZ.\n let haMultiplier = 1;\n if (isMultiAz) {\n if (targetProvider === \"gcp\") {\n const gcpMult = parseFloat(\n dbPrice.attributes?.ha_multiplier ?? \"2\"\n );\n haMultiplier = isNaN(gcpMult) ? 2 : gcpMult;\n } else {\n haMultiplier = 2;\n }\n notes.push(`Multi-AZ enabled: instance cost multiplied by ${haMultiplier}`);\n }\n\n const adjustedCost = instanceMonthlyCost * haMultiplier;\n breakdown.push({\n description: `${effectiveInstance} DB instance (${monthlyHours}h/month)${isMultiAz ? \" x\" + haMultiplier + \" (Multi-AZ)\" : \"\"}`,\n unit: \"Hrs\",\n quantity: monthlyHours * haMultiplier,\n unit_price: dbPrice.price_per_unit,\n monthly_cost: adjustedCost,\n });\n instanceMonthlyCost = adjustedCost;\n } else {\n notes.push(`No pricing data found for ${resource.type} in ${targetRegion}`);\n logger.debug(\"calculateDatabaseCost: no price\", {\n effectiveInstance,\n targetRegion,\n });\n }\n\n // Storage cost.\n let storageMonthlyCost = 0;\n if (allocatedStorageGb > 0) {\n // Use gp3 as the default EBS-style storage type for DB storage pricing.\n const storageType =\n (resource.attributes.storage_type as string | undefined) ?? \"gp3\";\n\n const storagePrice = await pricingEngine\n .getProvider(targetProvider)\n .getStoragePrice(storageType, targetRegion, allocatedStorageGb);\n\n if (storagePrice) {\n storageMonthlyCost = storagePrice.price_per_unit * allocatedStorageGb;\n breakdown.push({\n description: `DB storage ${storageType} (${allocatedStorageGb} GB)`,\n unit: \"GB-Mo\",\n quantity: allocatedStorageGb,\n unit_price: storagePrice.price_per_unit,\n monthly_cost: storageMonthlyCost,\n });\n }\n }\n\n const totalMonthly = instanceMonthlyCost + storageMonthlyCost;\n\n return {\n resource_id: resource.id,\n resource_type: resource.type,\n resource_name: resource.name,\n provider: targetProvider,\n region: targetRegion,\n monthly_cost: totalMonthly,\n yearly_cost: totalMonthly * 12,\n currency: \"USD\",\n breakdown,\n confidence: mappedInstance ? \"high\" : \"low\",\n notes,\n pricing_source: pricingSource,\n };\n}\n","import type { ParsedResource } from \"../types/resources.js\";\nimport type { CloudProvider } from \"../types/resources.js\";\nimport type { CostEstimate, CostLineItem } from \"../types/pricing.js\";\nimport type { PricingEngine } from \"../pricing/pricing-engine.js\";\nimport { mapStorageType } from \"../mapping/storage-mapper.js\";\nimport { logger } from \"../logger.js\";\n\n// Default size assumption for object storage buckets that have no explicit\n// size annotation in the Terraform configuration.\nconst DEFAULT_OBJECT_STORAGE_GB = 100;\n\n// Well-known Terraform resource types that represent block storage volumes.\nconst BLOCK_STORAGE_RESOURCE_TYPES = new Set([\n \"aws_ebs_volume\",\n \"azurerm_managed_disk\",\n \"google_compute_disk\",\n]);\n\n// Provider-specific fallback storage types to use when the mapped type cannot\n// be priced (e.g. object storage class names that don't exist in EBS tables).\n// For AWS, gp3 is the general-purpose type with a reliable fallback price.\nconst BLOCK_STORAGE_FALLBACK: Record<string, string> = {\n aws: \"gp3\",\n azure: \"Premium_LRS\",\n gcp: \"pd-ssd\",\n};\n\n/**\n * Determines whether a parsed resource represents block storage (e.g. EBS,\n * Managed Disk, Persistent Disk) vs object storage (S3, Blob Storage, GCS).\n */\nfunction isBlockStorage(resource: ParsedResource): boolean {\n return BLOCK_STORAGE_RESOURCE_TYPES.has(resource.type);\n}\n\n/**\n * Calculates the monthly storage cost for block or object storage resources.\n *\n * Block storage: storage_size_gb * price_per_gb_month\n * Object storage: size is taken from attributes if present, otherwise the\n * DEFAULT_OBJECT_STORAGE_GB assumption is used and noted.\n */\nexport async function calculateStorageCost(\n resource: ParsedResource,\n targetProvider: CloudProvider,\n targetRegion: string,\n pricingEngine: PricingEngine\n): Promise<CostEstimate> {\n const notes: string[] = [];\n const breakdown: CostLineItem[] = [];\n\n const block = isBlockStorage(resource);\n\n // Resolve storage type from attributes.\n const sourceStorageType =\n (resource.attributes.storage_type as string | undefined) ??\n (resource.attributes.type as string | undefined) ??\n (resource.attributes.storage_class as string | undefined) ??\n (block ? \"gp3\" : \"STANDARD\");\n\n const mappedStorageType =\n mapStorageType(sourceStorageType, resource.provider, targetProvider) ??\n sourceStorageType;\n\n // Resolve size.\n let sizeGb =\n (resource.attributes.storage_size_gb as number | undefined) ??\n (resource.attributes.disk_size_gb as number | undefined) ??\n (resource.attributes.size as number | undefined);\n\n if (!sizeGb || sizeGb <= 0) {\n if (block) {\n // Block volumes with no explicit size default to 8 GB (provider minimum).\n sizeGb = 8;\n notes.push(\"No storage size specified; defaulting to 8 GB for block volume\");\n } else {\n sizeGb = DEFAULT_OBJECT_STORAGE_GB;\n notes.push(\n `No storage size specified; assuming ${DEFAULT_OBJECT_STORAGE_GB} GB for object storage cost estimate`\n );\n }\n }\n\n // Fetch price. For object storage, provider pricing APIs may not recognise\n // storage-class names (e.g. \"STANDARD\", \"Hot\") as valid EBS/disk types.\n // Fall back to a provider-appropriate block storage type so the estimate\n // always produces a non-zero result for the caller.\n let resolvedStorageType = mappedStorageType;\n let storagePrice = await pricingEngine\n .getProvider(targetProvider)\n .getStoragePrice(resolvedStorageType, targetRegion, sizeGb);\n\n if (!storagePrice && !block) {\n // Object storage class could not be priced directly; use the provider's\n // general-purpose block storage fallback rate as a proxy.\n const fallbackType = BLOCK_STORAGE_FALLBACK[targetProvider];\n if (fallbackType) {\n storagePrice = await pricingEngine\n .getProvider(targetProvider)\n .getStoragePrice(fallbackType, targetRegion, sizeGb);\n if (storagePrice) {\n resolvedStorageType = fallbackType;\n notes.push(\n `Object storage class \"${mappedStorageType}\" not directly priced; using ${fallbackType} rate as an approximation`\n );\n }\n }\n }\n\n let totalMonthly = 0;\n let pricingSource: \"live\" | \"fallback\" | \"bundled\" = \"fallback\";\n\n if (storagePrice) {\n const rawSource = storagePrice.attributes?.pricing_source;\n if (rawSource === \"bundled\") {\n pricingSource = \"bundled\";\n } else if (rawSource === \"fallback\") {\n pricingSource = \"fallback\";\n notes.push(`Pricing for ${resolvedStorageType} uses bundled fallback data (live API unavailable)`);\n } else {\n pricingSource = \"live\";\n }\n\n totalMonthly = storagePrice.price_per_unit * sizeGb;\n breakdown.push({\n description: `${block ? \"Block\" : \"Object\"} storage ${resolvedStorageType} (${sizeGb} GB)`,\n unit: \"GB-Mo\",\n quantity: sizeGb,\n unit_price: storagePrice.price_per_unit,\n monthly_cost: totalMonthly,\n });\n } else {\n notes.push(\n `No pricing data found for ${resource.type} in ${targetRegion}`\n );\n logger.debug(\"calculateStorageCost: no price\", {\n mappedStorageType,\n targetRegion,\n });\n }\n\n return {\n resource_id: resource.id,\n resource_type: resource.type,\n resource_name: resource.name,\n provider: targetProvider,\n region: targetRegion,\n monthly_cost: totalMonthly,\n yearly_cost: totalMonthly * 12,\n currency: \"USD\",\n breakdown,\n confidence: storagePrice ? \"high\" : \"low\",\n notes,\n pricing_source: pricingSource,\n };\n}\n","import type { ParsedResource } from \"../types/resources.js\";\nimport type { CloudProvider } from \"../types/resources.js\";\nimport type { CostEstimate, CostLineItem } from \"../types/pricing.js\";\nimport type { PricingEngine } from \"../pricing/pricing-engine.js\";\n\n// Assumed data processing volume (GB/month) for NAT gateway cost estimates\n// when no explicit traffic figure is available in the resource attributes.\nconst DEFAULT_NAT_DATA_GB = 100;\n\n/**\n * Calculates the monthly cost for a NAT gateway resource.\n *\n * Cost = hourly_price * monthly_hours + per_gb_price * data_gb\n *\n * The data processing component uses an estimate when the Terraform resource\n * does not specify a traffic volume.\n */\nexport async function calculateNatGatewayCost(\n resource: ParsedResource,\n targetProvider: CloudProvider,\n targetRegion: string,\n pricingEngine: PricingEngine,\n monthlyHours: number = 730\n): Promise<CostEstimate> {\n const notes: string[] = [];\n const breakdown: CostLineItem[] = [];\n\n const natPrice = await pricingEngine\n .getProvider(targetProvider)\n .getNatGatewayPrice(targetRegion);\n\n let totalMonthly = 0;\n let natPricingSource: \"live\" | \"fallback\" | \"bundled\" = \"fallback\";\n\n if (natPrice) {\n const rawSource = natPrice.attributes?.pricing_source;\n if (rawSource === \"bundled\") {\n natPricingSource = \"bundled\";\n } else if (rawSource === \"fallback\") {\n natPricingSource = \"fallback\";\n } else {\n natPricingSource = \"live\";\n }\n\n const hourlyCharge = natPrice.price_per_unit * monthlyHours;\n breakdown.push({\n description: `NAT Gateway hourly charge (${monthlyHours}h/month)`,\n unit: \"Hrs\",\n quantity: monthlyHours,\n unit_price: natPrice.price_per_unit,\n monthly_cost: hourlyCharge,\n });\n totalMonthly += hourlyCharge;\n\n // Data processing component.\n const perGbPrice = parseFloat(\n natPrice.attributes?.per_gb_price ?? \"0\"\n );\n if (perGbPrice > 0) {\n const dataGb =\n (resource.attributes.data_processed_gb as number | undefined) ??\n DEFAULT_NAT_DATA_GB;\n\n if (\n !resource.attributes.data_processed_gb ||\n (resource.attributes.data_processed_gb as number) <= 0\n ) {\n notes.push(\n `Data processing cost estimated at ${dataGb} GB/month; provide data_processed_gb attribute for accuracy`\n );\n }\n\n const dataCharge = perGbPrice * dataGb;\n breakdown.push({\n description: `NAT Gateway data processing (${dataGb} GB/month)`,\n unit: \"GB\",\n quantity: dataGb,\n unit_price: perGbPrice,\n monthly_cost: dataCharge,\n });\n totalMonthly += dataCharge;\n }\n } else {\n notes.push(`No pricing data found for ${resource.type} in ${targetRegion}`);\n }\n\n return {\n resource_id: resource.id,\n resource_type: resource.type,\n resource_name: resource.name,\n provider: targetProvider,\n region: targetRegion,\n monthly_cost: totalMonthly,\n yearly_cost: totalMonthly * 12,\n currency: \"USD\",\n breakdown,\n confidence: natPrice ? \"medium\" : \"low\",\n notes,\n pricing_source: natPricingSource,\n };\n}\n\n/**\n * Calculates the monthly cost for a load balancer resource.\n *\n * Cost = hourly_price * monthly_hours (fixed component only; LCU/RCU-based\n * traffic charges are excluded as they require runtime traffic data).\n */\nexport async function calculateLoadBalancerCost(\n resource: ParsedResource,\n targetProvider: CloudProvider,\n targetRegion: string,\n pricingEngine: PricingEngine,\n monthlyHours: number = 730\n): Promise<CostEstimate> {\n const notes: string[] = [];\n const breakdown: CostLineItem[] = [];\n\n const lbType =\n (resource.attributes.load_balancer_type as string | undefined) ?? \"application\";\n\n const lbPrice = await pricingEngine\n .getProvider(targetProvider)\n .getLoadBalancerPrice(lbType, targetRegion);\n\n let totalMonthly = 0;\n let lbPricingSource: \"live\" | \"fallback\" | \"bundled\" = \"fallback\";\n\n if (lbPrice) {\n const rawSource = lbPrice.attributes?.pricing_source;\n if (rawSource === \"bundled\") {\n lbPricingSource = \"bundled\";\n } else if (rawSource === \"fallback\") {\n lbPricingSource = \"fallback\";\n } else {\n lbPricingSource = \"live\";\n }\n\n totalMonthly = lbPrice.price_per_unit * monthlyHours;\n breakdown.push({\n description: `Load Balancer hourly charge (${monthlyHours}h/month)`,\n unit: \"Hrs\",\n quantity: monthlyHours,\n unit_price: lbPrice.price_per_unit,\n monthly_cost: totalMonthly,\n });\n notes.push(\n \"Traffic-based charges (LCU/data processing) are excluded; this is the fixed hourly component only\"\n );\n } else {\n notes.push(`No pricing data found for ${resource.type} in ${targetRegion}`);\n }\n\n return {\n resource_id: resource.id,\n resource_type: resource.type,\n resource_name: resource.name,\n provider: targetProvider,\n region: targetRegion,\n monthly_cost: totalMonthly,\n yearly_cost: totalMonthly * 12,\n currency: \"USD\",\n breakdown,\n confidence: lbPrice ? \"medium\" : \"low\",\n notes,\n pricing_source: lbPricingSource,\n };\n}\n","import type { ParsedResource } from \"../types/resources.js\";\nimport type { CloudProvider } from \"../types/resources.js\";\nimport type { CostEstimate, CostLineItem } from \"../types/pricing.js\";\nimport type { PricingEngine } from \"../pricing/pricing-engine.js\";\nimport { calculateComputeCost } from \"./compute.js\";\n\n/**\n * Calculates the monthly cost for a Kubernetes cluster (EKS/AKS/GKE).\n *\n * Cost components:\n * 1. Control plane: hourly_price * monthly_hours\n * 2. Node groups: if node_count is available on the cluster resource itself,\n * the compute cost per node is estimated and multiplied by node_count.\n *\n * Node group resources (aws_eks_node_group, google_container_node_pool, etc.)\n * should be costed separately through calculateComputeCost; this function\n * handles only the cluster-level control plane charges.\n */\nexport async function calculateKubernetesCost(\n resource: ParsedResource,\n targetProvider: CloudProvider,\n targetRegion: string,\n pricingEngine: PricingEngine,\n monthlyHours: number = 730\n): Promise<CostEstimate> {\n const notes: string[] = [];\n const breakdown: CostLineItem[] = [];\n\n // Control plane pricing.\n const k8sPrice = await pricingEngine\n .getProvider(targetProvider)\n .getKubernetesPrice(targetRegion);\n\n let totalMonthly = 0;\n let pricingSource: \"live\" | \"fallback\" | \"bundled\" = \"fallback\";\n\n if (k8sPrice) {\n const rawSource = k8sPrice.attributes?.pricing_source;\n if (rawSource === \"bundled\") {\n pricingSource = \"bundled\";\n } else if (rawSource === \"fallback\") {\n pricingSource = \"fallback\";\n } else {\n pricingSource = \"live\";\n }\n\n const controlPlaneCost = k8sPrice.price_per_unit * monthlyHours;\n breakdown.push({\n description: `Kubernetes control plane (${monthlyHours}h/month)`,\n unit: \"Hrs\",\n quantity: monthlyHours,\n unit_price: k8sPrice.price_per_unit,\n monthly_cost: controlPlaneCost,\n });\n totalMonthly += controlPlaneCost;\n } else {\n notes.push(`No pricing data found for ${resource.type} in ${targetRegion}`);\n }\n\n // Optional: node group cost if node_count is embedded in cluster attributes.\n const nodeCount =\n (resource.attributes.node_count as number | undefined) ??\n (resource.attributes.min_node_count as number | undefined);\n\n if (nodeCount && nodeCount > 0) {\n const nodeInstanceType =\n (resource.attributes.instance_type as string | undefined) ??\n (resource.attributes.vm_size as string | undefined) ??\n (resource.attributes.machine_type as string | undefined);\n\n if (nodeInstanceType) {\n // Construct a synthetic compute resource for a single node to price it.\n const nodeResource: ParsedResource = {\n ...resource,\n id: `${resource.id}/node`,\n type: \"compute_node\",\n name: `${resource.name}-node`,\n attributes: {\n instance_type: nodeInstanceType,\n vm_size: nodeInstanceType,\n machine_type: nodeInstanceType,\n },\n };\n\n const nodeCostEstimate = await calculateComputeCost(\n nodeResource,\n targetProvider,\n targetRegion,\n pricingEngine,\n monthlyHours\n );\n\n if (nodeCostEstimate.monthly_cost > 0) {\n const nodeGroupCost = nodeCostEstimate.monthly_cost * nodeCount;\n breakdown.push({\n description: `${nodeCount}x node (${nodeInstanceType}) compute`,\n unit: \"nodes\",\n quantity: nodeCount,\n unit_price: nodeCostEstimate.monthly_cost,\n monthly_cost: nodeGroupCost,\n });\n totalMonthly += nodeGroupCost;\n notes.push(\n `Node cost estimated for ${nodeCount} nodes of type ${nodeInstanceType}`\n );\n }\n } else {\n notes.push(\n `node_count=${nodeCount} specified but no instance_type found; node compute cost excluded`\n );\n }\n }\n\n return {\n resource_id: resource.id,\n resource_type: resource.type,\n resource_name: resource.name,\n provider: targetProvider,\n region: targetRegion,\n monthly_cost: totalMonthly,\n yearly_cost: totalMonthly * 12,\n currency: \"USD\",\n breakdown,\n confidence: k8sPrice ? \"medium\" : \"low\",\n notes,\n pricing_source: pricingSource,\n };\n}\n","import type { ParsedResource, CloudProvider } from \"../types/resources.js\";\nimport type { CostEstimate, CostBreakdown } from \"../types/pricing.js\";\nimport type { CloudCostConfig } from \"../types/config.js\";\nimport type { PricingEngine } from \"../pricing/pricing-engine.js\";\nimport { calculateComputeCost } from \"./compute.js\";\nimport { calculateDatabaseCost } from \"./database.js\";\nimport { calculateStorageCost } from \"./storage.js\";\nimport { calculateNatGatewayCost, calculateLoadBalancerCost } from \"./network.js\";\nimport { calculateKubernetesCost } from \"./kubernetes.js\";\nimport { logger } from \"../logger.js\";\n\n// ---------------------------------------------------------------------------\n// Resource type classification\n// ---------------------------------------------------------------------------\n\nconst COMPUTE_TYPES = new Set([\n \"aws_instance\",\n \"azurerm_linux_virtual_machine\",\n \"azurerm_windows_virtual_machine\",\n \"google_compute_instance\",\n // Node groups – cost their compute like VMs.\n \"aws_eks_node_group\",\n \"azurerm_kubernetes_cluster_node_pool\",\n \"google_container_node_pool\",\n \"compute_node\",\n]);\n\nconst DATABASE_TYPES = new Set([\n \"aws_db_instance\",\n \"azurerm_postgresql_flexible_server\",\n \"azurerm_mysql_flexible_server\",\n \"azurerm_mssql_server\",\n \"google_sql_database_instance\",\n]);\n\nconst BLOCK_STORAGE_TYPES = new Set([\n \"aws_ebs_volume\",\n \"azurerm_managed_disk\",\n \"google_compute_disk\",\n]);\n\nconst OBJECT_STORAGE_TYPES = new Set([\n \"aws_s3_bucket\",\n \"azurerm_storage_account\",\n \"google_storage_bucket\",\n]);\n\nconst NAT_GATEWAY_TYPES = new Set([\n \"aws_nat_gateway\",\n \"azurerm_nat_gateway\",\n \"google_compute_router_nat\",\n]);\n\nconst LOAD_BALANCER_TYPES = new Set([\n \"aws_lb\",\n \"aws_alb\",\n \"azurerm_lb\",\n \"azurerm_application_gateway\",\n \"google_compute_forwarding_rule\",\n]);\n\nconst KUBERNETES_TYPES = new Set([\n \"aws_eks_cluster\",\n \"azurerm_kubernetes_cluster\",\n \"google_container_cluster\",\n]);\n\n// ---------------------------------------------------------------------------\n// Service label helper (for by_service aggregation)\n// ---------------------------------------------------------------------------\n\nfunction serviceLabel(resourceType: string): string {\n if (COMPUTE_TYPES.has(resourceType)) return \"compute\";\n if (DATABASE_TYPES.has(resourceType)) return \"database\";\n if (BLOCK_STORAGE_TYPES.has(resourceType)) return \"block_storage\";\n if (OBJECT_STORAGE_TYPES.has(resourceType)) return \"object_storage\";\n if (NAT_GATEWAY_TYPES.has(resourceType)) return \"network\";\n if (LOAD_BALANCER_TYPES.has(resourceType)) return \"network\";\n if (KUBERNETES_TYPES.has(resourceType)) return \"kubernetes\";\n return \"other\";\n}\n\n// ---------------------------------------------------------------------------\n// CostEngine\n// ---------------------------------------------------------------------------\n\n/**\n * CostEngine is the top-level orchestrator for multi-cloud cost estimation.\n *\n * It dispatches each ParsedResource to the appropriate sub-calculator based on\n * resource type, collects the resulting CostEstimate objects, and aggregates\n * them into a CostBreakdown with per-service totals.\n */\nexport class CostEngine {\n private pricingEngine: PricingEngine;\n private monthlyHours: number;\n\n constructor(pricingEngine: PricingEngine, config: CloudCostConfig) {\n this.pricingEngine = pricingEngine;\n this.monthlyHours = config.pricing.monthly_hours;\n }\n\n /**\n * Calculates the cost of a single resource on a target provider.\n */\n async calculateCost(\n resource: ParsedResource,\n targetProvider: CloudProvider,\n targetRegion: string\n ): Promise<CostEstimate> {\n const type = resource.type;\n\n logger.debug(\"CostEngine.calculateCost\", {\n resourceId: resource.id,\n type,\n targetProvider,\n targetRegion,\n });\n\n if (COMPUTE_TYPES.has(type)) {\n return calculateComputeCost(\n resource,\n targetProvider,\n targetRegion,\n this.pricingEngine,\n this.monthlyHours\n );\n }\n\n if (DATABASE_TYPES.has(type)) {\n return calculateDatabaseCost(\n resource,\n targetProvider,\n targetRegion,\n this.pricingEngine,\n this.monthlyHours\n );\n }\n\n if (BLOCK_STORAGE_TYPES.has(type) || OBJECT_STORAGE_TYPES.has(type)) {\n return calculateStorageCost(\n resource,\n targetProvider,\n targetRegion,\n this.pricingEngine\n );\n }\n\n if (NAT_GATEWAY_TYPES.has(type)) {\n return calculateNatGatewayCost(\n resource,\n targetProvider,\n targetRegion,\n this.pricingEngine,\n this.monthlyHours\n );\n }\n\n if (LOAD_BALANCER_TYPES.has(type)) {\n return calculateLoadBalancerCost(\n resource,\n targetProvider,\n targetRegion,\n this.pricingEngine,\n this.monthlyHours\n );\n }\n\n if (KUBERNETES_TYPES.has(type)) {\n return calculateKubernetesCost(\n resource,\n targetProvider,\n targetRegion,\n this.pricingEngine,\n this.monthlyHours\n );\n }\n\n // Unsupported resource type – return a zero-cost estimate so callers can\n // still include it in the breakdown without crashing.\n logger.warn(\"CostEngine: unsupported resource type\", { type, targetProvider });\n return {\n resource_id: resource.id,\n resource_type: type,\n resource_name: resource.name,\n provider: targetProvider,\n region: targetRegion,\n monthly_cost: 0,\n yearly_cost: 0,\n currency: \"USD\",\n breakdown: [],\n confidence: \"low\",\n notes: [`Resource type \"${type}\" is not yet supported by the cost engine`],\n pricing_source: \"fallback\" as const,\n };\n }\n\n /**\n * Calculates costs for all resources and aggregates them into a CostBreakdown.\n *\n * Resources that fail to produce a cost estimate are logged and skipped rather\n * than letting a single failure abort the entire calculation.\n */\n async calculateBreakdown(\n resources: ParsedResource[],\n targetProvider: CloudProvider,\n targetRegion: string\n ): Promise<CostBreakdown> {\n const estimates: CostEstimate[] = [];\n const byService: Record<string, number> = {};\n const warnings: string[] = [];\n\n for (const resource of resources) {\n try {\n const estimate = await this.calculateCost(\n resource,\n targetProvider,\n targetRegion\n );\n estimates.push(estimate);\n\n const svc = serviceLabel(resource.type);\n byService[svc] = (byService[svc] ?? 0) + estimate.monthly_cost;\n\n // Surface warnings for fallback pricing and missing data.\n if (estimate.pricing_source === \"fallback\") {\n warnings.push(\n `${estimate.resource_name} (${estimate.resource_type}): using fallback/bundled pricing data`\n );\n }\n if (estimate.monthly_cost === 0 && estimate.confidence === \"low\") {\n warnings.push(\n `No pricing data found for ${estimate.resource_type} in ${targetRegion} — cost reported as $0`\n );\n }\n } catch (err) {\n logger.error(\"CostEngine: failed to calculate cost for resource\", {\n resourceId: resource.id,\n type: resource.type,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n const totalMonthly = estimates.reduce((sum, e) => sum + e.monthly_cost, 0);\n\n return {\n provider: targetProvider,\n region: targetRegion,\n total_monthly: Math.round(totalMonthly * 100) / 100,\n total_yearly: Math.round(totalMonthly * 12 * 100) / 100,\n currency: \"USD\",\n by_service: byService,\n by_resource: estimates,\n generated_at: new Date().toISOString(),\n warnings,\n };\n }\n}\n","import { z } from \"zod\";\nimport type { CloudProvider } from \"../types/resources.js\";\nimport type { CloudCostConfig } from \"../types/config.js\";\nimport type { ProviderComparison, CostBreakdown, SavingsSummary } from \"../types/pricing.js\";\nimport type { PricingEngine } from \"../pricing/pricing-engine.js\";\nimport { parseTerraform } from \"../parsers/index.js\";\nimport { mapRegion } from \"../mapping/region-mapper.js\";\nimport { CostEngine } from \"../calculator/cost-engine.js\";\nimport { generateMarkdownReport } from \"../reporting/markdown-report.js\";\nimport { generateJsonReport } from \"../reporting/json-report.js\";\nimport { generateCsvReport } from \"../reporting/csv-report.js\";\n\n// ---------------------------------------------------------------------------\n// Schema\n// ---------------------------------------------------------------------------\n\nexport const compareProvidersSchema = z.object({\n files: z.array(\n z.object({\n path: z.string().describe(\"File path\"),\n content: z.string().describe(\"File content (HCL)\"),\n })\n ),\n tfvars: z.string().optional().describe(\"Contents of terraform.tfvars file\"),\n format: z\n .enum([\"markdown\", \"json\", \"csv\"])\n .default(\"markdown\")\n .describe(\"Output report format\"),\n providers: z\n .array(z.enum([\"aws\", \"azure\", \"gcp\"]))\n .default([\"aws\", \"azure\", \"gcp\"])\n .describe(\"Cloud providers to include in the comparison\"),\n});\n\n// ---------------------------------------------------------------------------\n// Handler\n// ---------------------------------------------------------------------------\n\n/**\n * Parse the supplied Terraform files, calculate costs across all requested\n * providers, and return a formatted report together with the raw comparison\n * data.\n */\nexport async function compareProviders(\n params: z.infer<typeof compareProvidersSchema>,\n pricingEngine: PricingEngine,\n config: CloudCostConfig\n): Promise<object> {\n const inventory = await parseTerraform(params.files, params.tfvars);\n const sourceProvider = inventory.provider;\n const costEngine = new CostEngine(pricingEngine, config);\n const comparisons: CostBreakdown[] = [];\n\n for (const provider of params.providers as CloudProvider[]) {\n const targetRegion = mapRegion(inventory.region, sourceProvider, provider);\n const breakdown = await costEngine.calculateBreakdown(\n inventory.resources,\n provider,\n targetRegion\n );\n comparisons.push(breakdown);\n }\n\n // Build a savings summary relative to the source provider breakdown (or the\n // first breakdown when the source provider was not requested).\n const sourceBreakdown =\n comparisons.find((b) => b.provider === sourceProvider) ?? comparisons[0];\n const sourceMonthly = sourceBreakdown?.total_monthly ?? 0;\n\n const savingsSummary: SavingsSummary[] = comparisons.map((b) => {\n const diff = b.total_monthly - sourceMonthly;\n const pct =\n sourceMonthly !== 0 ? (diff / sourceMonthly) * 100 : 0;\n return {\n provider: b.provider,\n total_monthly: b.total_monthly,\n difference_from_source: Math.round(diff * 100) / 100,\n percentage_difference: Math.round(pct * 10) / 10,\n };\n });\n\n const comparison: ProviderComparison = {\n source_provider: sourceProvider,\n comparisons,\n savings_summary: savingsSummary,\n generated_at: new Date().toISOString(),\n };\n\n // Aggregate warnings for use in reports.\n const allWarnings = comparisons.flatMap((b) => b.warnings ?? []);\n const parseWarnings = inventory.parse_warnings ?? [];\n const monthlyHours = config.pricing.monthly_hours;\n\n // Format the report according to the requested format.\n let report: string;\n switch (params.format) {\n case \"json\":\n report = generateJsonReport(comparison, inventory.resources, monthlyHours, parseWarnings);\n break;\n case \"csv\":\n report = generateCsvReport(comparison, inventory.resources);\n break;\n case \"markdown\":\n default:\n report = generateMarkdownReport(\n comparison,\n inventory.resources,\n {},\n parseWarnings\n );\n break;\n }\n\n return {\n report,\n format: params.format,\n comparison,\n warnings: [...new Set([...parseWarnings, ...allWarnings])],\n };\n}\n","import type { CloudProvider } from \"../types/resources.js\";\n\n/**\n * Represents a single reserved instance pricing option (term + payment model).\n */\nexport interface ReservedOption {\n term: \"1yr\" | \"3yr\";\n payment: \"no_upfront\" | \"all_upfront\" | \"partial_upfront\";\n monthly_cost: number;\n monthly_savings: number;\n percentage_savings: number;\n}\n\n/**\n * A full reserved-pricing comparison for a resource showing on-demand cost\n * alongside all available reserved purchase options.\n */\nexport interface ReservedComparison {\n on_demand_monthly: number;\n options: ReservedOption[];\n best_option: ReservedOption;\n}\n\n// Discount rates sourced from published provider documentation (approximate).\n// AWS: https://aws.amazon.com/ec2/pricing/reserved-instances/pricing/\n// Azure: https://azure.microsoft.com/en-us/pricing/reserved-vm-instances/\n// GCP: https://cloud.google.com/compute/docs/sustained-use-discounts\nconst DISCOUNT_RATES: Record<\n CloudProvider,\n Array<{ term: \"1yr\" | \"3yr\"; payment: ReservedOption[\"payment\"]; rate: number }>\n> = {\n aws: [\n { term: \"1yr\", payment: \"no_upfront\", rate: 0.36 },\n { term: \"1yr\", payment: \"partial_upfront\", rate: 0.40 },\n { term: \"1yr\", payment: \"all_upfront\", rate: 0.42 },\n { term: \"3yr\", payment: \"no_upfront\", rate: 0.52 },\n { term: \"3yr\", payment: \"partial_upfront\", rate: 0.57 },\n { term: \"3yr\", payment: \"all_upfront\", rate: 0.60 },\n ],\n azure: [\n { term: \"1yr\", payment: \"all_upfront\", rate: 0.35 },\n { term: \"3yr\", payment: \"all_upfront\", rate: 0.55 },\n // Azure does not offer no-upfront RI in the same way; partial_upfront maps\n // to hybrid benefit combined, approximated here.\n { term: \"1yr\", payment: \"partial_upfront\", rate: 0.30 },\n { term: \"3yr\", payment: \"partial_upfront\", rate: 0.50 },\n ],\n gcp: [\n // GCP Committed Use Discounts (CUDs) – resource-based.\n { term: \"1yr\", payment: \"all_upfront\", rate: 0.28 },\n { term: \"3yr\", payment: \"all_upfront\", rate: 0.55 },\n { term: \"1yr\", payment: \"partial_upfront\", rate: 0.20 },\n { term: \"3yr\", payment: \"partial_upfront\", rate: 0.45 },\n ],\n};\n\n/**\n * Calculates reserved / committed-use pricing options for a resource given its\n * on-demand monthly cost.\n *\n * The returned comparison includes all available purchase options for the\n * provider plus a convenience best_option pointing to the highest-savings\n * all-upfront option.\n */\nexport function calculateReservedPricing(\n onDemandMonthly: number,\n provider: CloudProvider\n): ReservedComparison {\n const rates = DISCOUNT_RATES[provider];\n\n const options: ReservedOption[] = rates.map(({ term, payment, rate }) => {\n const monthly_cost = onDemandMonthly * (1 - rate);\n const monthly_savings = onDemandMonthly - monthly_cost;\n return {\n term,\n payment,\n monthly_cost: Math.round(monthly_cost * 100) / 100,\n monthly_savings: Math.round(monthly_savings * 100) / 100,\n percentage_savings: Math.round(rate * 1000) / 10, // e.g. 36.0\n };\n });\n\n // Best option = highest savings (last entry in our sorted-by-savings array).\n const best_option = options.reduce(\n (best, opt) =>\n opt.monthly_savings > best.monthly_savings ? opt : best,\n options[0]\n );\n\n return {\n on_demand_monthly: Math.round(onDemandMonthly * 100) / 100,\n options,\n best_option,\n };\n}\n","import type { ParsedResource } from \"../types/resources.js\";\nimport type { CostEstimate } from \"../types/pricing.js\";\nimport type { OptimizationRecommendation } from \"../types/reports.js\";\nimport { calculateReservedPricing } from \"./reserved.js\";\n\n// ---------------------------------------------------------------------------\n// Instance size heuristics\n// ---------------------------------------------------------------------------\n\n// Instance type size suffixes that are considered \"xlarge or bigger\".\n// Used to identify potentially over-provisioned instances.\nconst LARGE_INSTANCE_SUFFIXES = [\n \".xlarge\",\n \".2xlarge\",\n \".4xlarge\",\n \".8xlarge\",\n \".16xlarge\",\n \"Standard_B4ms\",\n \"Standard_B8ms\",\n \"Standard_D4\",\n \"Standard_D8\",\n \"Standard_D16\",\n \"Standard_E4\",\n \"Standard_E8\",\n \"n2-standard-4\",\n \"n2-standard-8\",\n \"n2-standard-16\",\n \"e2-standard-4\",\n \"e2-standard-8\",\n];\n\n// Tags / attribute indicators that suggest the instance is genuinely busy and\n// right-sizing would be inappropriate.\nconst HIGH_UTILISATION_INDICATORS = [\n \"high-cpu\",\n \"high-memory\",\n \"production\",\n \"prod\",\n \"perf\",\n \"performance\",\n];\n\nfunction isLikelyOversized(resource: ParsedResource): boolean {\n const instanceType =\n (resource.attributes.instance_type as string | undefined) ??\n (resource.attributes.vm_size as string | undefined) ??\n (resource.attributes.machine_type as string | undefined) ??\n \"\";\n\n const isLarge = LARGE_INSTANCE_SUFFIXES.some((suffix) =>\n instanceType.toLowerCase().includes(suffix.toLowerCase())\n );\n if (!isLarge) return false;\n\n // If tags suggest it is a high-utilisation workload, do not suggest\n // right-sizing.\n const tagValues = Object.values(resource.tags).map((v) => v.toLowerCase());\n const tagKeys = Object.keys(resource.tags).map((k) => k.toLowerCase());\n const allTagText = [...tagKeys, ...tagValues].join(\" \");\n\n const hasHighUtilisationSignal = HIGH_UTILISATION_INDICATORS.some((signal) =>\n allTagText.includes(signal)\n );\n\n return !hasHighUtilisationSignal;\n}\n\n// ---------------------------------------------------------------------------\n// Compute resource type identifiers\n// ---------------------------------------------------------------------------\n\nconst COMPUTE_RESOURCE_TYPES = new Set([\n \"aws_instance\",\n \"azurerm_linux_virtual_machine\",\n \"azurerm_windows_virtual_machine\",\n \"google_compute_instance\",\n \"aws_eks_cluster\",\n \"aws_eks_node_group\",\n \"azurerm_kubernetes_cluster\",\n \"google_container_cluster\",\n \"google_container_node_pool\",\n]);\n\nconst DATABASE_RESOURCE_TYPES = new Set([\n \"aws_db_instance\",\n \"azurerm_postgresql_flexible_server\",\n \"azurerm_mysql_flexible_server\",\n \"google_sql_database_instance\",\n]);\n\nconst OBJECT_STORAGE_RESOURCE_TYPES = new Set([\n \"aws_s3_bucket\",\n \"azurerm_storage_account\",\n \"google_storage_bucket\",\n]);\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Generates cost optimisation recommendations from a set of cost estimates\n * and their corresponding parsed resource definitions.\n *\n * Recommendation types produced:\n * - right_size: Instance appears over-provisioned\n * - reserved: Switching to reserved/committed pricing would save money\n * - switch_provider: Another provider is significantly cheaper (>20% savings)\n * - storage_tier: Object storage could use a cheaper tier\n */\nexport function generateOptimizations(\n estimates: CostEstimate[],\n resources: ParsedResource[]\n): OptimizationRecommendation[] {\n const recommendations: OptimizationRecommendation[] = [];\n\n // Build a lookup from resource_id to ParsedResource for quick access.\n const resourceById = new Map<string, ParsedResource>(\n resources.map((r) => [r.id, r])\n );\n\n // Group estimates by resource_id so we can compare providers.\n const estimatesByResourceId = new Map<string, CostEstimate[]>();\n for (const estimate of estimates) {\n const existing = estimatesByResourceId.get(estimate.resource_id) ?? [];\n existing.push(estimate);\n estimatesByResourceId.set(estimate.resource_id, existing);\n }\n\n for (const [resourceId, resourceEstimates] of estimatesByResourceId) {\n const resource = resourceById.get(resourceId);\n if (!resourceEstimates.length) continue;\n\n // Use the first estimate as the \"current\" provider cost for recommendations.\n const current = resourceEstimates[0];\n\n // Right-sizing recommendation.\n if (resource && COMPUTE_RESOURCE_TYPES.has(resource.type)) {\n if (isLikelyOversized(resource) && current.monthly_cost > 0) {\n // Estimate savings at 30% (moving down one instance size tier).\n const estimatedSavings = current.monthly_cost * 0.30;\n recommendations.push({\n resource_id: resourceId,\n resource_name: current.resource_name,\n type: \"right_size\",\n description:\n `${resource.attributes.instance_type ?? resource.attributes.vm_size ?? \"Instance\"} ` +\n `appears over-provisioned. Consider downsizing to the next smaller instance type.`,\n current_monthly_cost: current.monthly_cost,\n estimated_monthly_cost: current.monthly_cost - estimatedSavings,\n monthly_savings: estimatedSavings,\n percentage_savings: 30,\n confidence: \"medium\",\n provider: current.provider,\n });\n }\n }\n\n // Reserved instance recommendation for compute and DB resources.\n if (\n resource &&\n (COMPUTE_RESOURCE_TYPES.has(resource.type) ||\n DATABASE_RESOURCE_TYPES.has(resource.type)) &&\n current.monthly_cost > 0\n ) {\n const reserved = calculateReservedPricing(\n current.monthly_cost,\n current.provider\n );\n const best = reserved.best_option;\n\n if (best.percentage_savings >= 20) {\n recommendations.push({\n resource_id: resourceId,\n resource_name: current.resource_name,\n type: \"reserved\",\n description:\n `Switching to a ${best.term} ${best.payment.replace(/_/g, \" \")} commitment ` +\n `could save approximately ${best.percentage_savings}% per month.`,\n current_monthly_cost: current.monthly_cost,\n estimated_monthly_cost: best.monthly_cost,\n monthly_savings: best.monthly_savings,\n percentage_savings: best.percentage_savings,\n confidence: \"high\",\n provider: current.provider,\n });\n }\n }\n\n // Switch provider recommendation (compare all provider estimates for the resource).\n if (resourceEstimates.length > 1 && current.monthly_cost > 0) {\n const cheapest = resourceEstimates.reduce(\n (min, e) => (e.monthly_cost < min.monthly_cost ? e : min),\n current\n );\n\n if (cheapest.provider !== current.provider) {\n const savings = current.monthly_cost - cheapest.monthly_cost;\n const pct = (savings / current.monthly_cost) * 100;\n\n if (pct >= 20) {\n recommendations.push({\n resource_id: resourceId,\n resource_name: current.resource_name,\n type: \"switch_provider\",\n description:\n `${cheapest.provider.toUpperCase()} offers this resource at $${cheapest.monthly_cost.toFixed(2)}/month ` +\n `vs $${current.monthly_cost.toFixed(2)}/month on ${current.provider.toUpperCase()}, ` +\n `saving approximately ${pct.toFixed(0)}%.`,\n current_monthly_cost: current.monthly_cost,\n estimated_monthly_cost: cheapest.monthly_cost,\n monthly_savings: savings,\n percentage_savings: Math.round(pct * 10) / 10,\n confidence: \"medium\",\n provider: cheapest.provider,\n });\n }\n }\n }\n\n // Object storage tier recommendation.\n if (resource && OBJECT_STORAGE_RESOURCE_TYPES.has(resource.type)) {\n const storageClass =\n (resource.attributes.storage_class as string | undefined) ?? \"\";\n const isHotTier =\n storageClass === \"\" ||\n storageClass.toLowerCase() === \"standard\" ||\n storageClass.toLowerCase() === \"hot\";\n\n if (isHotTier && current.monthly_cost > 0) {\n const estimatedSavings = current.monthly_cost * 0.40;\n recommendations.push({\n resource_id: resourceId,\n resource_name: current.resource_name,\n type: \"storage_tier\",\n description:\n \"Consider using an infrequent-access or cool storage tier if data is not accessed daily. \" +\n \"This can reduce storage costs by ~40–60%.\",\n current_monthly_cost: current.monthly_cost,\n estimated_monthly_cost: current.monthly_cost - estimatedSavings,\n monthly_savings: estimatedSavings,\n percentage_savings: 40,\n confidence: \"low\",\n provider: current.provider,\n });\n }\n }\n }\n\n return recommendations;\n}\n","import type { ProviderComparison, CostBreakdown } from \"../types/pricing.js\";\nimport type { ParsedResource } from \"../types/resources.js\";\nimport type { CloudProvider } from \"../types/resources.js\";\nimport type { ReportOptions } from \"../types/reports.js\";\nimport { generateOptimizations } from \"../calculator/optimizer.js\";\n\nconst PROVIDERS: CloudProvider[] = [\"aws\", \"azure\", \"gcp\"];\n\nfunction formatUsd(amount: number): string {\n return `$${amount.toFixed(2)}`;\n}\n\nfunction providerLabel(provider: CloudProvider): string {\n switch (provider) {\n case \"aws\":\n return \"AWS\";\n case \"azure\":\n return \"Azure\";\n case \"gcp\":\n return \"GCP\";\n }\n}\n\n/**\n * Generates a Markdown cost comparison report.\n *\n * Sections:\n * 1. Title and generation date\n * 2. Summary table (provider, monthly cost, yearly cost, vs source)\n * 3. Per-resource breakdown table (resource, type, cost per provider)\n * 4. Savings recommendations (if include_recommendations is true)\n * 5. Assumptions\n * 6. Limitations (only when parse warnings or data quality warnings exist)\n */\nexport function generateMarkdownReport(\n comparison: ProviderComparison,\n resources: ParsedResource[],\n options: Partial<ReportOptions> = {},\n parseWarnings: string[] = []\n): string {\n const includeBreakdown = options.include_breakdown !== false;\n const includeRecommendations = options.include_recommendations !== false;\n const monthlyHours = (options as { monthly_hours?: number }).monthly_hours ?? 730;\n\n const lines: string[] = [];\n const now = new Date().toISOString().split(\"T\")[0];\n\n // ---------------------------------------------------------------------------\n // Title\n // ---------------------------------------------------------------------------\n lines.push(\n `# Cloud Cost Comparison Report`,\n ``,\n `**Generated:** ${now} `,\n `**Source provider:** ${providerLabel(comparison.source_provider)} `,\n `**Resources analysed:** ${resources.length}`,\n ``\n );\n\n // ---------------------------------------------------------------------------\n // Summary table\n // ---------------------------------------------------------------------------\n lines.push(`## Summary`, ``);\n\n // Find source provider breakdown for \"vs source\" column.\n const sourceBreakdown = comparison.comparisons.find(\n (b) => b.provider === comparison.source_provider\n );\n const sourceMonthly = sourceBreakdown?.total_monthly ?? 0;\n\n lines.push(\n `| Provider | Monthly Cost | Yearly Cost | vs Source |`,\n `|----------|-------------|------------|-----------|`\n );\n\n for (const breakdown of comparison.comparisons) {\n const diff = breakdown.total_monthly - sourceMonthly;\n const diffLabel =\n breakdown.provider === comparison.source_provider\n ? \"—\"\n : diff < 0\n ? `${formatUsd(Math.abs(diff))} cheaper`\n : diff > 0\n ? `${formatUsd(diff)} more expensive`\n : \"same cost\";\n\n lines.push(\n `| ${providerLabel(breakdown.provider)} | ${formatUsd(breakdown.total_monthly)} | ${formatUsd(breakdown.total_yearly)} | ${diffLabel} |`\n );\n }\n lines.push(``);\n\n // ---------------------------------------------------------------------------\n // Savings summary\n // ---------------------------------------------------------------------------\n if (comparison.savings_summary.length > 0) {\n lines.push(`## Savings Potential`, ``);\n lines.push(\n `| Provider | Monthly Cost | Savings from Source | Savings % |`,\n `|----------|-------------|--------------------|-----------| `\n );\n for (const s of comparison.savings_summary) {\n const savings = s.difference_from_source;\n const savingsLabel =\n savings < 0\n ? formatUsd(Math.abs(savings))\n : `-${formatUsd(savings)}`;\n const pct =\n s.percentage_difference < 0\n ? `${Math.abs(s.percentage_difference).toFixed(1)}% cheaper`\n : `${s.percentage_difference.toFixed(1)}% more`;\n lines.push(\n `| ${providerLabel(s.provider)} | ${formatUsd(s.total_monthly)} | ${savingsLabel} | ${pct} |`\n );\n }\n lines.push(``);\n }\n\n // ---------------------------------------------------------------------------\n // Per-resource breakdown\n // ---------------------------------------------------------------------------\n if (includeBreakdown && resources.length > 0) {\n lines.push(`## Resource Breakdown`, ``);\n\n // Build: resource_id -> provider -> monthly_cost\n const costMatrix = new Map<string, Partial<Record<CloudProvider, number>>>();\n\n for (const breakdown of comparison.comparisons) {\n for (const estimate of breakdown.by_resource) {\n const row = costMatrix.get(estimate.resource_id) ?? {};\n row[breakdown.provider] = estimate.monthly_cost;\n costMatrix.set(estimate.resource_id, row);\n }\n }\n\n // Table header – only include columns for providers that appear in the comparison.\n const presentProviders = comparison.comparisons.map((b) => b.provider);\n const headerCols = presentProviders\n .map((p) => providerLabel(p))\n .join(\" | \");\n\n lines.push(\n `| Resource | Type | ${headerCols} |`,\n `|----------|------|${presentProviders.map(() => \"------\").join(\"|\")}|`\n );\n\n for (const resource of resources) {\n const costs = costMatrix.get(resource.id) ?? {};\n const costCols = presentProviders\n .map((p) => formatUsd(costs[p] ?? 0))\n .join(\" | \");\n lines.push(\n `| ${resource.name} | ${resource.type} | ${costCols} |`\n );\n }\n lines.push(``);\n }\n\n // ---------------------------------------------------------------------------\n // Optimisation recommendations\n // ---------------------------------------------------------------------------\n if (includeRecommendations) {\n // Collect all estimates across all provider breakdowns.\n const allEstimates = comparison.comparisons.flatMap((b) => b.by_resource);\n const recommendations = generateOptimizations(allEstimates, resources);\n\n if (recommendations.length > 0) {\n lines.push(`## Savings Recommendations`, ``);\n\n for (const rec of recommendations) {\n const savingsLabel = `${formatUsd(rec.monthly_savings)}/month (${rec.percentage_savings}%)`;\n lines.push(\n `### ${rec.resource_name} – ${rec.type.replace(/_/g, \" \")}`,\n ``,\n `${rec.description}`,\n ``,\n `- **Current cost:** ${formatUsd(rec.current_monthly_cost)}/month`,\n `- **Estimated after:** ${formatUsd(rec.estimated_monthly_cost)}/month`,\n `- **Potential savings:** ${savingsLabel}`,\n `- **Confidence:** ${rec.confidence}`,\n ``\n );\n }\n } else {\n lines.push(`## Savings Recommendations`, ``, `No recommendations at this time.`, ``);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Assumptions\n // ---------------------------------------------------------------------------\n lines.push(`## Assumptions`, ``);\n lines.push(\n `| Parameter | Value |`,\n `|-----------|-------|`,\n `| Pricing model | On-demand (no reserved or spot instances) |`,\n `| Operating system | Linux (unless specified in resource attributes) |`,\n `| Monthly hours | ${monthlyHours} |`,\n `| Currency | USD |`,\n `| Pricing source | Mix of live API and fallback/bundled data |`,\n `| Data transfer costs | Not included |`,\n `| Tax | Not included |`,\n ``\n );\n\n // ---------------------------------------------------------------------------\n // Limitations\n // ---------------------------------------------------------------------------\n // Collect all data quality warnings across all provider breakdowns.\n const allDataWarnings = comparison.comparisons.flatMap((b) => b.warnings ?? []);\n const allWarnings = [...new Set([...parseWarnings, ...allDataWarnings])];\n\n if (allWarnings.length > 0) {\n lines.push(`## Limitations`, ``);\n lines.push(\n `> The following issues were detected during analysis that may affect estimate accuracy:`,\n ``\n );\n for (const w of allWarnings) {\n lines.push(`- ${w}`);\n }\n lines.push(``);\n }\n\n return lines.join(\"\\n\");\n}\n","import type { ProviderComparison } from \"../types/pricing.js\";\nimport type { ParsedResource } from \"../types/resources.js\";\n\n/**\n * Generates a pretty-printed JSON representation of the full provider\n * comparison, augmented with a metadata section and a resource summary.\n *\n * The metadata section contains:\n * - generated_at timestamp\n * - pricing_sources_used (unique sources referenced across all estimates)\n * - assumptions (static estimation parameters)\n * - warnings (data quality issues collected across all breakdowns)\n */\nexport function generateJsonReport(\n comparison: ProviderComparison,\n resources: ParsedResource[],\n monthlyHours: number = 730,\n parseWarnings: string[] = []\n): string {\n // Collect unique pricing sources across all resource estimates.\n const sourcesSet = new Set<string>();\n for (const breakdown of comparison.comparisons) {\n for (const estimate of breakdown.by_resource) {\n const src = estimate.pricing_source;\n if (src) {\n sourcesSet.add(`${breakdown.provider}_${src}`);\n }\n }\n }\n\n // Aggregate all data quality warnings, deduplicated.\n const allDataWarnings = comparison.comparisons.flatMap((b) => b.warnings ?? []);\n const allWarnings = [...new Set([...parseWarnings, ...allDataWarnings])];\n\n const output = {\n metadata: {\n generated_at: new Date().toISOString(),\n pricing_sources_used: Array.from(sourcesSet).sort(),\n assumptions: {\n pricing_model: \"on-demand\",\n operating_system: \"Linux (unless specified)\",\n monthly_hours: monthlyHours,\n currency: \"USD\",\n data_transfer_costs: \"not included\",\n tax: \"not included\",\n },\n warnings: allWarnings,\n },\n ...comparison,\n resource_summary: {\n total: resources.length,\n by_type: resources.reduce<Record<string, number>>((acc, r) => {\n acc[r.type] = (acc[r.type] ?? 0) + 1;\n return acc;\n }, {}),\n },\n };\n\n return JSON.stringify(output, null, 2);\n}\n","import type { ProviderComparison } from \"../types/pricing.js\";\nimport type { ParsedResource } from \"../types/resources.js\";\nimport type { CloudProvider } from \"../types/resources.js\";\n\nconst PROVIDERS: CloudProvider[] = [\"aws\", \"azure\", \"gcp\"];\n\nfunction csvEscape(value: string | number): string {\n const str = String(value);\n // Wrap in double quotes if the value contains a comma, newline, or quote.\n if (str.includes(\",\") || str.includes(\"\\n\") || str.includes('\"')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n}\n\n/**\n * Generates a CSV report comparing monthly costs across all providers for\n * each resource.\n *\n * Columns: Resource, Type, AWS Monthly, Azure Monthly, GCP Monthly, Cheapest\n */\nexport function generateCsvReport(\n comparison: ProviderComparison,\n resources: ParsedResource[]\n): string {\n const lines: string[] = [];\n\n // Comment header: not part of the CSV data but provides context to readers.\n lines.push(\"# Prices are estimates based on on-demand pricing. See assumptions in JSON/Markdown reports.\");\n\n // Column header row.\n lines.push(\"Resource,Type,AWS Monthly,Azure Monthly,GCP Monthly,Cheapest\");\n\n // Build a lookup: provider -> (resource_id -> monthly_cost).\n const costByProviderAndResource = new Map<string, Map<string, number>>();\n for (const breakdown of comparison.comparisons) {\n const byResource = new Map<string, number>();\n for (const estimate of breakdown.by_resource) {\n byResource.set(estimate.resource_id, estimate.monthly_cost);\n }\n costByProviderAndResource.set(breakdown.provider, byResource);\n }\n\n // One row per resource.\n for (const resource of resources) {\n const costs: Partial<Record<CloudProvider, number>> = {};\n for (const provider of PROVIDERS) {\n const providerMap = costByProviderAndResource.get(provider);\n if (providerMap) {\n costs[provider] = providerMap.get(resource.id) ?? 0;\n }\n }\n\n // Find the cheapest provider that has a non-zero cost.\n let cheapest = \"N/A\";\n let lowestCost = Infinity;\n for (const provider of PROVIDERS) {\n const cost = costs[provider] ?? 0;\n if (cost > 0 && cost < lowestCost) {\n lowestCost = cost;\n cheapest = provider.toUpperCase();\n }\n }\n\n const row = [\n csvEscape(resource.name),\n csvEscape(resource.type),\n csvEscape((costs.aws ?? 0).toFixed(2)),\n csvEscape((costs.azure ?? 0).toFixed(2)),\n csvEscape((costs.gcp ?? 0).toFixed(2)),\n csvEscape(cheapest),\n ];\n\n lines.push(row.join(\",\"));\n }\n\n return lines.join(\"\\n\");\n}\n","import { z } from \"zod\";\nimport type { CloudProvider } from \"../types/resources.js\";\nimport { findEquivalent, findAllEquivalents } from \"../mapping/resource-mapper.js\";\nimport { mapInstance } from \"../mapping/instance-mapper.js\";\n\n// ---------------------------------------------------------------------------\n// Schema\n// ---------------------------------------------------------------------------\n\nexport const getEquivalentsSchema = z.object({\n resource_type: z\n .string()\n .describe(\n \"Terraform resource type to look up (e.g. aws_instance, google_compute_instance)\"\n ),\n source_provider: z\n .enum([\"aws\", \"azure\", \"gcp\"])\n .describe(\"Cloud provider the resource type belongs to\"),\n target_provider: z\n .enum([\"aws\", \"azure\", \"gcp\"])\n .optional()\n .describe(\n \"Specific target provider. When omitted, equivalents for all providers are returned.\"\n ),\n instance_type: z\n .string()\n .optional()\n .describe(\n \"Instance type / VM size to also map across providers (e.g. t3.large, Standard_D4s_v3)\"\n ),\n});\n\n// ---------------------------------------------------------------------------\n// Handler\n// ---------------------------------------------------------------------------\n\n/**\n * Return the cross-provider resource type equivalents for a given Terraform\n * resource type. Optionally also maps an instance type when provided.\n */\nexport async function getEquivalents(\n params: z.infer<typeof getEquivalentsSchema>\n): Promise<object> {\n const sourceProvider = params.source_provider as CloudProvider;\n\n // Resource-type equivalents\n let resourceEquivalents: Partial<Record<string, string | null>>;\n\n if (params.target_provider) {\n const targetProvider = params.target_provider as CloudProvider;\n const equivalent = findEquivalent(\n params.resource_type,\n sourceProvider,\n targetProvider\n );\n resourceEquivalents = { [targetProvider]: equivalent };\n } else {\n resourceEquivalents = findAllEquivalents(params.resource_type, sourceProvider);\n }\n\n // Instance-type equivalents (optional)\n let instanceEquivalents:\n | Partial<Record<string, string | null>>\n | undefined;\n\n if (params.instance_type) {\n const providers: CloudProvider[] = [\"aws\", \"azure\", \"gcp\"];\n const targets = params.target_provider\n ? [params.target_provider as CloudProvider]\n : providers.filter((p) => p !== sourceProvider);\n\n instanceEquivalents = {};\n for (const target of targets) {\n instanceEquivalents[target] = mapInstance(\n params.instance_type,\n sourceProvider,\n target\n );\n }\n }\n\n return {\n resource_type: params.resource_type,\n source_provider: sourceProvider,\n resource_equivalents: resourceEquivalents,\n ...(instanceEquivalents !== undefined\n ? {\n instance_type: params.instance_type,\n instance_equivalents: instanceEquivalents,\n }\n : {}),\n };\n}\n","import type { CloudProvider } from \"../types/resources.js\";\nimport type { ResourceEquivalent } from \"../types/mapping.js\";\nimport { getResourceEquivalents } from \"../data/loader.js\";\n\n/**\n * Finds the equivalent resource type on a target provider for a given\n * resource type on a source provider.\n *\n * The lookup is bidirectional: the source provider column is searched for an\n * exact match against resourceType, and the target provider column value is\n * returned. Returns null when no mapping exists.\n */\nexport function findEquivalent(\n resourceType: string,\n sourceProvider: CloudProvider,\n targetProvider: CloudProvider\n): string | null {\n if (sourceProvider === targetProvider) {\n return resourceType;\n }\n\n const equivalents = getResourceEquivalents();\n const row = equivalents.find(\n (entry) => entry[sourceProvider] === resourceType\n );\n\n if (!row) return null;\n return row[targetProvider] ?? null;\n}\n\n/**\n * Returns a mapping of all known equivalent resource types across every\n * provider for a given source resource type. Providers that have no\n * equivalent are omitted from the result.\n */\nexport function findAllEquivalents(\n resourceType: string,\n sourceProvider: CloudProvider\n): Record<CloudProvider, string> {\n const equivalents = getResourceEquivalents();\n const row = equivalents.find(\n (entry) => entry[sourceProvider] === resourceType\n );\n\n if (!row) return {} as Record<CloudProvider, string>;\n\n const result: Partial<Record<CloudProvider, string>> = {};\n const providers: CloudProvider[] = [\"aws\", \"azure\", \"gcp\"];\n\n for (const provider of providers) {\n const value = (row as ResourceEquivalent)[provider];\n if (value) {\n result[provider] = value;\n }\n }\n\n return result as Record<CloudProvider, string>;\n}\n","import { z } from \"zod\";\nimport type { CloudProvider } from \"../types/resources.js\";\nimport type { PricingEngine } from \"../pricing/pricing-engine.js\";\n\n// ---------------------------------------------------------------------------\n// Schema\n// ---------------------------------------------------------------------------\n\nexport const getPricingSchema = z.object({\n provider: z\n .enum([\"aws\", \"azure\", \"gcp\"])\n .describe(\"Cloud provider to look up pricing for\"),\n service: z\n .enum([\"compute\", \"database\", \"storage\", \"network\", \"kubernetes\"])\n .describe(\"Service category\"),\n resource_type: z\n .string()\n .describe(\n \"Instance type, storage type, or resource identifier (e.g. t3.large, gp3, Standard_D4s_v3)\"\n ),\n region: z.string().describe(\"Cloud region (e.g. us-east-1, eastus, us-central1)\"),\n});\n\n// ---------------------------------------------------------------------------\n// Handler\n// ---------------------------------------------------------------------------\n\n/**\n * Perform a direct pricing lookup via the PricingEngine and return the\n * NormalizedPrice for the requested combination of provider, service,\n * resource type, and region.\n *\n * Returns null in the `price` field when no pricing data is available.\n */\nexport async function getPricing(\n params: z.infer<typeof getPricingSchema>,\n pricingEngine: PricingEngine\n): Promise<object> {\n const provider = params.provider as CloudProvider;\n\n // Map the user-facing service enum to an internal service identifier that\n // PricingEngine.getPrice() recognises.\n const serviceMap: Record<string, string> = {\n compute: \"compute\",\n database: \"database\",\n storage: \"storage\",\n network: \"nat-gateway\",\n kubernetes: \"kubernetes\",\n };\n\n const service = serviceMap[params.service] ?? params.service;\n\n const price = await pricingEngine.getPrice(\n provider,\n service,\n params.resource_type,\n params.region\n );\n\n return {\n provider,\n service: params.service,\n resource_type: params.resource_type,\n region: params.region,\n price,\n };\n}\n","import { z } from \"zod\";\nimport type { CloudProvider } from \"../types/resources.js\";\nimport type { CloudCostConfig } from \"../types/config.js\";\nimport type { CostEstimate } from \"../types/pricing.js\";\nimport type { PricingEngine } from \"../pricing/pricing-engine.js\";\nimport { parseTerraform } from \"../parsers/index.js\";\nimport { mapRegion } from \"../mapping/region-mapper.js\";\nimport { CostEngine } from \"../calculator/cost-engine.js\";\nimport { generateOptimizations } from \"../calculator/optimizer.js\";\nimport { calculateReservedPricing } from \"../calculator/reserved.js\";\n\n// ---------------------------------------------------------------------------\n// Schema\n// ---------------------------------------------------------------------------\n\nexport const optimizeCostSchema = z.object({\n files: z.array(\n z.object({\n path: z.string().describe(\"File path\"),\n content: z.string().describe(\"File content (HCL)\"),\n })\n ),\n tfvars: z.string().optional().describe(\"Contents of terraform.tfvars file\"),\n providers: z\n .array(z.enum([\"aws\", \"azure\", \"gcp\"]))\n .default([\"aws\", \"azure\", \"gcp\"])\n .describe(\"Providers to calculate costs against for cross-provider recommendations\"),\n});\n\n// ---------------------------------------------------------------------------\n// Handler\n// ---------------------------------------------------------------------------\n\n/**\n * Parse the supplied Terraform files, calculate costs across all requested\n * providers, and return optimisation recommendations together with reserved\n * pricing comparisons.\n */\nexport async function optimizeCost(\n params: z.infer<typeof optimizeCostSchema>,\n pricingEngine: PricingEngine,\n config: CloudCostConfig\n): Promise<object> {\n const inventory = await parseTerraform(params.files, params.tfvars);\n const sourceProvider = inventory.provider;\n const costEngine = new CostEngine(pricingEngine, config);\n\n // Collect all cost estimates across every requested provider so the\n // optimizer can issue switch_provider recommendations when appropriate.\n const allEstimates: CostEstimate[] = [];\n\n for (const provider of params.providers as CloudProvider[]) {\n const targetRegion = mapRegion(inventory.region, sourceProvider, provider);\n const breakdown = await costEngine.calculateBreakdown(\n inventory.resources,\n provider,\n targetRegion\n );\n allEstimates.push(...breakdown.by_resource);\n }\n\n const recommendations = generateOptimizations(allEstimates, inventory.resources);\n\n // Build reserved pricing comparisons for every resource that has a non-zero\n // cost on the source provider so users can see committed-use savings at a\n // glance without navigating to a separate tool call.\n const sourceEstimates = allEstimates.filter(\n (e) => e.provider === sourceProvider && e.monthly_cost > 0\n );\n\n const reservedPricing = sourceEstimates.map((estimate) => ({\n resource_id: estimate.resource_id,\n resource_name: estimate.resource_name,\n resource_type: estimate.resource_type,\n provider: estimate.provider,\n ...calculateReservedPricing(estimate.monthly_cost, estimate.provider),\n }));\n\n const totalPotentialSavings =\n recommendations.reduce((sum, r) => sum + r.monthly_savings, 0);\n\n return {\n recommendations,\n reserved_pricing: reservedPricing,\n total_potential_savings: Math.round(totalPotentialSavings * 100) / 100,\n recommendation_count: recommendations.length,\n resource_count: inventory.resources.length,\n };\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { CloudCostConfig } from \"../types/config.js\";\nimport { PricingCache } from \"../pricing/cache.js\";\nimport { PricingEngine } from \"../pricing/pricing-engine.js\";\n\nimport {\n analyzeTerraformSchema,\n analyzeTerraform,\n} from \"./analyze-terraform.js\";\nimport { estimateCostSchema, estimateCost } from \"./estimate-cost.js\";\nimport {\n compareProvidersSchema,\n compareProviders,\n} from \"./compare-providers.js\";\nimport {\n getEquivalentsSchema,\n getEquivalents,\n} from \"./get-equivalents.js\";\nimport { getPricingSchema, getPricing } from \"./get-pricing.js\";\nimport { optimizeCostSchema, optimizeCost } from \"./optimize-cost.js\";\n\n// ---------------------------------------------------------------------------\n// Tool registration\n// ---------------------------------------------------------------------------\n\n/**\n * Register all CloudCost MCP tools on the provided McpServer instance.\n *\n * A single PricingCache and PricingEngine are shared across all tools so\n * that the SQLite cache is opened exactly once per server lifetime.\n */\nexport function registerTools(server: McpServer, config: CloudCostConfig): void {\n const cache = new PricingCache(config.cache.db_path);\n const pricingEngine = new PricingEngine(cache, config);\n\n // -------------------------------------------------------------------------\n // analyze_terraform\n // -------------------------------------------------------------------------\n server.tool(\n \"analyze_terraform\",\n \"Parse Terraform HCL files and extract a resource inventory with provider detection, variable resolution, and cost-relevant attribute extraction\",\n analyzeTerraformSchema.shape,\n async (params) => {\n const result = await analyzeTerraform(params);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result, null, 2) }],\n };\n }\n );\n\n // -------------------------------------------------------------------------\n // estimate_cost\n // -------------------------------------------------------------------------\n server.tool(\n \"estimate_cost\",\n \"Estimate monthly and yearly cloud costs for Terraform resources on a specific provider. Returns a full cost breakdown by resource and service category.\",\n estimateCostSchema.shape,\n async (params) => {\n const result = await estimateCost(params, pricingEngine, config);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result, null, 2) }],\n };\n }\n );\n\n // -------------------------------------------------------------------------\n // compare_providers\n // -------------------------------------------------------------------------\n server.tool(\n \"compare_providers\",\n \"Run a full cost comparison across AWS, Azure, and GCP for a set of Terraform resources. Returns a formatted report and raw comparison data including savings potential.\",\n compareProvidersSchema.shape,\n async (params) => {\n const result = await compareProviders(params, pricingEngine, config);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result, null, 2) }],\n };\n }\n );\n\n // -------------------------------------------------------------------------\n // get_equivalents\n // -------------------------------------------------------------------------\n server.tool(\n \"get_equivalents\",\n \"Look up the equivalent Terraform resource types across cloud providers. Optionally also maps an instance type / VM size to the nearest equivalent on target providers.\",\n getEquivalentsSchema.shape,\n async (params) => {\n const result = await getEquivalents(params);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result, null, 2) }],\n };\n }\n );\n\n // -------------------------------------------------------------------------\n // get_pricing\n // -------------------------------------------------------------------------\n server.tool(\n \"get_pricing\",\n \"Direct pricing lookup for a specific cloud provider, service, resource type, and region. Returns the normalised unit price with metadata.\",\n getPricingSchema.shape,\n async (params) => {\n const result = await getPricing(params, pricingEngine);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result, null, 2) }],\n };\n }\n );\n\n // -------------------------------------------------------------------------\n // optimize_cost\n // -------------------------------------------------------------------------\n server.tool(\n \"optimize_cost\",\n \"Analyse Terraform resources and return cost optimisation recommendations including right-sizing suggestions, reserved pricing comparisons, and cross-provider savings opportunities.\",\n optimizeCostSchema.shape,\n async (params) => {\n const result = await optimizeCost(params, pricingEngine, config);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result, null, 2) }],\n };\n }\n );\n}\n","import { startServer } from \"./server.js\";\n\nprocess.on(\"uncaughtException\", (err) => {\n process.stderr.write(`Uncaught exception: ${err.stack ?? err.message}\\n`);\n process.exit(1);\n});\n\nprocess.on(\"unhandledRejection\", (reason) => {\n const msg = reason instanceof Error ? reason.stack ?? reason.message : String(reason);\n process.stderr.write(`Unhandled rejection: ${msg}\\n`);\n process.exit(1);\n});\n\nstartServer().catch((err) => {\n process.stderr.write(`Failed to start server: ${err.stack ?? err.message}\\n`);\n process.exit(1);\n});\n"],"mappings":"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","names":["ALB_HOURLY","NAT_HOURLY","NAT_PER_GB","REGION_MULTIPLIERS","regionMultiplier","CACHE_TTL","NAT_HOURLY","NAT_PER_GB","str","z","getInstanceMap","z","z","str","z","z","z","z","z","z"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}