cdk-cost-analyzer 0.1.1

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.
Files changed (228) hide show
  1. package/.cdk-cost-analyzer-cache/metadata.json +12 -0
  2. package/.gitlab-ci.yml +214 -0
  3. package/.husky/pre-commit +12 -0
  4. package/.kiro/hooks/accessibility-audit.kiro.hook +18 -0
  5. package/.kiro/hooks/api-schema-validation.kiro.hook +21 -0
  6. package/.kiro/hooks/auto-test-on-save.kiro.hook +19 -0
  7. package/.kiro/hooks/cdk-synth-on-change.kiro.hook +20 -0
  8. package/.kiro/hooks/code-coverage-check.kiro.hook +14 -0
  9. package/.kiro/hooks/commit-message-helper.kiro.hook +14 -0
  10. package/.kiro/hooks/dependency-update-check.kiro.hook +14 -0
  11. package/.kiro/hooks/env-file-validation.kiro.hook +18 -0
  12. package/.kiro/hooks/lint-and-format-on-save.kiro.hook +21 -0
  13. package/.kiro/hooks/mcp-config-validation.kiro.hook +17 -0
  14. package/.kiro/hooks/mcp-server-test.kiro.hook +14 -0
  15. package/.kiro/hooks/performance-analysis.kiro.hook +14 -0
  16. package/.kiro/hooks/readme-spell-check.kiro.hook +14 -0
  17. package/.kiro/hooks/security-scan-on-dependency-change.kiro.hook +21 -0
  18. package/.kiro/hooks/translation-update.kiro.hook +18 -0
  19. package/.kiro/hooks/update-documentation.kiro.hook +18 -0
  20. package/.kiro/settings/mcp.json +20 -0
  21. package/.kiro/specs/cdk-cost-analyzer/design.md +620 -0
  22. package/.kiro/specs/cdk-cost-analyzer/requirements.md +183 -0
  23. package/.kiro/specs/cdk-cost-analyzer/tasks.md +357 -0
  24. package/.kiro/specs/github-actions-ci/design.md +281 -0
  25. package/.kiro/specs/github-actions-ci/requirements.md +86 -0
  26. package/.kiro/specs/github-actions-ci/tasks.md +115 -0
  27. package/.kiro/specs/nlb-calculator-test-coverage/design.md +190 -0
  28. package/.kiro/specs/nlb-calculator-test-coverage/requirements.md +84 -0
  29. package/.kiro/specs/nlb-calculator-test-coverage/tasks.md +150 -0
  30. package/.kiro/specs/production-readiness/design.md +1213 -0
  31. package/.kiro/specs/production-readiness/requirements.md +312 -0
  32. package/.kiro/specs/production-readiness/tasks.md +269 -0
  33. package/.kiro/specs/repository-cleanup/design.md +283 -0
  34. package/.kiro/specs/repository-cleanup/requirements.md +74 -0
  35. package/.kiro/specs/repository-cleanup/tasks.md +64 -0
  36. package/.kiro/steering/aws-cli-best-practices.md +41 -0
  37. package/.kiro/steering/cdk-best-practices.md +49 -0
  38. package/.kiro/steering/development-standards.md +54 -0
  39. package/.kiro/steering/docker-best-practices.md +34 -0
  40. package/.kiro/steering/documentation-style.md +151 -0
  41. package/.kiro/steering/git-best-practices.md +37 -0
  42. package/.kiro/steering/mcp-best-practices.md +95 -0
  43. package/.kiro/steering/python-best-practices.md +48 -0
  44. package/.kiro/steering/react-best-practices.md +44 -0
  45. package/.kiro/steering/security-best-practices.md +41 -0
  46. package/.kiro/steering/testing-best-practices.md +59 -0
  47. package/.kiro/steering/typescript-best-practices.md +40 -0
  48. package/CHANGELOG.md +49 -0
  49. package/CONTRIBUTING.md +258 -0
  50. package/LICENSE +19 -0
  51. package/README.md +480 -0
  52. package/SECURITY.md +117 -0
  53. package/dist/api/index.d.ts +11 -0
  54. package/dist/api/index.js +65 -0
  55. package/dist/api/types.d.ts +15 -0
  56. package/dist/api/types.js +3 -0
  57. package/dist/cli/index.d.ts +2 -0
  58. package/dist/cli/index.js +262 -0
  59. package/dist/config/ConfigManager.d.ts +40 -0
  60. package/dist/config/ConfigManager.js +238 -0
  61. package/dist/config/index.d.ts +2 -0
  62. package/dist/config/index.js +19 -0
  63. package/dist/config/types.d.ts +72 -0
  64. package/dist/config/types.js +15 -0
  65. package/dist/diff/DiffEngine.d.ts +7 -0
  66. package/dist/diff/DiffEngine.js +73 -0
  67. package/dist/diff/index.d.ts +2 -0
  68. package/dist/diff/index.js +21 -0
  69. package/dist/diff/types.d.ts +20 -0
  70. package/dist/diff/types.js +3 -0
  71. package/dist/integrations/GitLabIntegration.d.ts +7 -0
  72. package/dist/integrations/GitLabIntegration.js +45 -0
  73. package/dist/integrations/index.d.ts +2 -0
  74. package/dist/integrations/index.js +21 -0
  75. package/dist/integrations/types.d.ts +11 -0
  76. package/dist/integrations/types.js +13 -0
  77. package/dist/parser/TemplateParser.d.ts +8 -0
  78. package/dist/parser/TemplateParser.js +75 -0
  79. package/dist/parser/index.d.ts +2 -0
  80. package/dist/parser/index.js +22 -0
  81. package/dist/parser/types.d.ts +30 -0
  82. package/dist/parser/types.js +3 -0
  83. package/dist/pipeline/PipelineOrchestrator.d.ts +23 -0
  84. package/dist/pipeline/PipelineOrchestrator.js +191 -0
  85. package/dist/pipeline/index.d.ts +2 -0
  86. package/dist/pipeline/index.js +19 -0
  87. package/dist/pipeline/types.d.ts +41 -0
  88. package/dist/pipeline/types.js +13 -0
  89. package/dist/pricing/CacheManager.d.ts +75 -0
  90. package/dist/pricing/CacheManager.js +195 -0
  91. package/dist/pricing/PricingClient.d.ts +17 -0
  92. package/dist/pricing/PricingClient.js +122 -0
  93. package/dist/pricing/PricingService.d.ts +16 -0
  94. package/dist/pricing/PricingService.js +149 -0
  95. package/dist/pricing/calculators/ALBCalculator.d.ts +16 -0
  96. package/dist/pricing/calculators/ALBCalculator.js +163 -0
  97. package/dist/pricing/calculators/APIGatewayCalculator.d.ts +10 -0
  98. package/dist/pricing/calculators/APIGatewayCalculator.js +177 -0
  99. package/dist/pricing/calculators/CloudFrontCalculator.d.ts +59 -0
  100. package/dist/pricing/calculators/CloudFrontCalculator.js +151 -0
  101. package/dist/pricing/calculators/DynamoDBCalculator.d.ts +9 -0
  102. package/dist/pricing/calculators/DynamoDBCalculator.js +146 -0
  103. package/dist/pricing/calculators/EC2Calculator.d.ts +7 -0
  104. package/dist/pricing/calculators/EC2Calculator.js +80 -0
  105. package/dist/pricing/calculators/ECSCalculator.d.ts +9 -0
  106. package/dist/pricing/calculators/ECSCalculator.js +116 -0
  107. package/dist/pricing/calculators/ElastiCacheCalculator.d.ts +8 -0
  108. package/dist/pricing/calculators/ElastiCacheCalculator.js +106 -0
  109. package/dist/pricing/calculators/LambdaCalculator.d.ts +13 -0
  110. package/dist/pricing/calculators/LambdaCalculator.js +111 -0
  111. package/dist/pricing/calculators/NLBCalculator.d.ts +16 -0
  112. package/dist/pricing/calculators/NLBCalculator.js +138 -0
  113. package/dist/pricing/calculators/NatGatewayCalculator.d.ts +12 -0
  114. package/dist/pricing/calculators/NatGatewayCalculator.js +116 -0
  115. package/dist/pricing/calculators/RDSCalculator.d.ts +9 -0
  116. package/dist/pricing/calculators/RDSCalculator.js +103 -0
  117. package/dist/pricing/calculators/S3Calculator.d.ts +8 -0
  118. package/dist/pricing/calculators/S3Calculator.js +68 -0
  119. package/dist/pricing/calculators/VPCEndpointCalculator.d.ts +12 -0
  120. package/dist/pricing/calculators/VPCEndpointCalculator.js +129 -0
  121. package/dist/pricing/index.d.ts +10 -0
  122. package/dist/pricing/index.js +37 -0
  123. package/dist/pricing/types.d.ts +53 -0
  124. package/dist/pricing/types.js +22 -0
  125. package/dist/releasetag.txt +1 -0
  126. package/dist/reporter/Reporter.d.ts +18 -0
  127. package/dist/reporter/Reporter.js +412 -0
  128. package/dist/reporter/index.d.ts +2 -0
  129. package/dist/reporter/index.js +21 -0
  130. package/dist/reporter/types.d.ts +72 -0
  131. package/dist/reporter/types.js +3 -0
  132. package/dist/synthesis/SynthesisOrchestrator.d.ts +26 -0
  133. package/dist/synthesis/SynthesisOrchestrator.js +243 -0
  134. package/dist/synthesis/index.d.ts +2 -0
  135. package/dist/synthesis/index.js +19 -0
  136. package/dist/synthesis/types.d.ts +17 -0
  137. package/dist/synthesis/types.js +13 -0
  138. package/dist/threshold/ThresholdEnforcer.d.ts +29 -0
  139. package/dist/threshold/ThresholdEnforcer.js +143 -0
  140. package/dist/threshold/index.d.ts +2 -0
  141. package/dist/threshold/index.js +19 -0
  142. package/dist/threshold/types.d.ts +15 -0
  143. package/dist/threshold/types.js +17 -0
  144. package/docs/CALCULATORS.md +820 -0
  145. package/docs/CI_CD.md +608 -0
  146. package/docs/CONFIGURATION.md +407 -0
  147. package/docs/DEVELOPMENT.md +387 -0
  148. package/docs/RELEASE.md +223 -0
  149. package/docs/TROUBLESHOOTING.md +847 -0
  150. package/examples/.cdk-cost-analyzer.yml +85 -0
  151. package/examples/.gitlab-ci.yml +125 -0
  152. package/examples/api-usage.js +26 -0
  153. package/examples/complex/base.json +16 -0
  154. package/examples/complex/target.json +29 -0
  155. package/examples/monorepo/.gitlab-ci.yml +251 -0
  156. package/examples/monorepo/README.md +341 -0
  157. package/examples/monorepo/package.json +27 -0
  158. package/examples/monorepo/packages/backend-infra/.cdk-cost-analyzer.yml +34 -0
  159. package/examples/monorepo/packages/backend-infra/bin/app.ts +16 -0
  160. package/examples/monorepo/packages/backend-infra/cdk.json +7 -0
  161. package/examples/monorepo/packages/backend-infra/lib/backend-stack.ts +128 -0
  162. package/examples/monorepo/packages/backend-infra/package.json +30 -0
  163. package/examples/monorepo/packages/backend-infra/tsconfig.json +11 -0
  164. package/examples/monorepo/packages/data-infra/.cdk-cost-analyzer.yml +38 -0
  165. package/examples/monorepo/packages/data-infra/bin/app.ts +16 -0
  166. package/examples/monorepo/packages/data-infra/cdk.json +7 -0
  167. package/examples/monorepo/packages/data-infra/lib/data-stack.ts +121 -0
  168. package/examples/monorepo/packages/data-infra/package.json +30 -0
  169. package/examples/monorepo/packages/data-infra/tsconfig.json +11 -0
  170. package/examples/monorepo/packages/frontend-infra/.cdk-cost-analyzer.yml +31 -0
  171. package/examples/monorepo/packages/frontend-infra/bin/app.ts +16 -0
  172. package/examples/monorepo/packages/frontend-infra/cdk.json +7 -0
  173. package/examples/monorepo/packages/frontend-infra/lib/frontend-stack.ts +60 -0
  174. package/examples/monorepo/packages/frontend-infra/package.json +30 -0
  175. package/examples/monorepo/packages/frontend-infra/tsconfig.json +11 -0
  176. package/examples/monorepo/tsconfig.json +35 -0
  177. package/examples/multi-stack/.cdk-cost-analyzer.yml +72 -0
  178. package/examples/multi-stack/.gitlab-ci.yml +184 -0
  179. package/examples/multi-stack/README.md +279 -0
  180. package/examples/multi-stack/bin/app.ts +36 -0
  181. package/examples/multi-stack/cdk.json +72 -0
  182. package/examples/multi-stack/lib/compute-stack.ts +128 -0
  183. package/examples/multi-stack/lib/networking-stack.ts +69 -0
  184. package/examples/multi-stack/lib/storage-stack.ts +141 -0
  185. package/examples/multi-stack/package-lock.json +4437 -0
  186. package/examples/multi-stack/package.json +42 -0
  187. package/examples/multi-stack/tsconfig.json +34 -0
  188. package/examples/simple/base.json +8 -0
  189. package/examples/simple/target.json +14 -0
  190. package/examples/single-stack/.NVP +0 -0
  191. package/examples/single-stack/.cdk-cost-analyzer.yml +52 -0
  192. package/examples/single-stack/.gitlab-ci.yml +126 -0
  193. package/examples/single-stack/README.md +184 -0
  194. package/examples/single-stack/UeK +0 -0
  195. package/examples/single-stack/bin/app.ts +16 -0
  196. package/examples/single-stack/cdk.json +72 -0
  197. package/examples/single-stack/lib/infrastructure-stack.ts +119 -0
  198. package/examples/single-stack/package-lock.json +4443 -0
  199. package/examples/single-stack/package.json +38 -0
  200. package/examples/single-stack/tsconfig.json +34 -0
  201. package/package.json +139 -0
  202. package/test-cdk-project/README-COMPUTE.md +141 -0
  203. package/test-cdk-project/README.md +95 -0
  204. package/test-cdk-project/app-with-compute.js +102 -0
  205. package/test-cdk-project/app.js +81 -0
  206. package/test-cdk-project/cdk-compute.json +3 -0
  207. package/test-cdk-project/cdk.context.json +7 -0
  208. package/test-cdk-project/cdk.json +3 -0
  209. package/test-cdk-project/cdk.out/TestStack.assets.json +21 -0
  210. package/test-cdk-project/cdk.out/TestStack.template.json +115 -0
  211. package/test-cdk-project/cdk.out/cdk.out +1 -0
  212. package/test-cdk-project/cdk.out/manifest.json +503 -0
  213. package/test-cdk-project/cdk.out/tree.json +1 -0
  214. package/test-cdk-project/cdk.out.base/TestStack.assets.json +21 -0
  215. package/test-cdk-project/cdk.out.base/TestStack.template.json +115 -0
  216. package/test-cdk-project/cdk.out.base/cdk.out +1 -0
  217. package/test-cdk-project/cdk.out.base/manifest.json +503 -0
  218. package/test-cdk-project/cdk.out.base/tree.json +1 -0
  219. package/test-cdk-project/cdk.out.target/TestStack.assets.json +21 -0
  220. package/test-cdk-project/cdk.out.target/TestStack.template.json +183 -0
  221. package/test-cdk-project/cdk.out.target/cdk.out +1 -0
  222. package/test-cdk-project/cdk.out.target/manifest.json +521 -0
  223. package/test-cdk-project/cdk.out.target/tree.json +1 -0
  224. package/test-cdk-project/package-lock.json +422 -0
  225. package/test-cdk-project/package.json +17 -0
  226. package/tools/workflows/README.md +102 -0
  227. package/tools/workflows/validate-workflows.js +109 -0
  228. package/tools/workflows/workflow-utils.ts +181 -0
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EC2Calculator = void 0;
4
+ class EC2Calculator {
5
+ supports(resourceType) {
6
+ return resourceType === 'AWS::EC2::Instance';
7
+ }
8
+ async calculateCost(resource, region, pricingClient) {
9
+ const instanceType = resource.properties.InstanceType;
10
+ if (!instanceType) {
11
+ return {
12
+ amount: 0,
13
+ currency: 'USD',
14
+ confidence: 'unknown',
15
+ assumptions: ['Instance type not specified'],
16
+ };
17
+ }
18
+ try {
19
+ const hourlyRate = await pricingClient.getPrice({
20
+ serviceCode: 'AmazonEC2',
21
+ region: this.normalizeRegion(region),
22
+ filters: [
23
+ { field: 'instanceType', value: instanceType },
24
+ { field: 'operatingSystem', value: 'Linux' },
25
+ { field: 'tenancy', value: 'Shared' },
26
+ { field: 'preInstalledSw', value: 'NA' },
27
+ { field: 'capacitystatus', value: 'Used' },
28
+ ],
29
+ });
30
+ if (hourlyRate === null) {
31
+ return {
32
+ amount: 0,
33
+ currency: 'USD',
34
+ confidence: 'unknown',
35
+ assumptions: [`Pricing data not available for instance type ${instanceType} in region ${region}`],
36
+ };
37
+ }
38
+ const monthlyHours = 730;
39
+ const monthlyCost = hourlyRate * monthlyHours;
40
+ return {
41
+ amount: monthlyCost,
42
+ currency: 'USD',
43
+ confidence: 'high',
44
+ assumptions: [
45
+ `Assumes ${monthlyHours} hours per month (24/7 operation)`,
46
+ 'Assumes Linux OS, shared tenancy, on-demand pricing',
47
+ ],
48
+ };
49
+ }
50
+ catch (error) {
51
+ return {
52
+ amount: 0,
53
+ currency: 'USD',
54
+ confidence: 'unknown',
55
+ assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
56
+ };
57
+ }
58
+ }
59
+ normalizeRegion(region) {
60
+ const regionMap = {
61
+ 'us-east-1': 'US East (N. Virginia)',
62
+ 'us-east-2': 'US East (Ohio)',
63
+ 'us-west-1': 'US West (N. California)',
64
+ 'us-west-2': 'US West (Oregon)',
65
+ 'eu-west-1': 'EU (Ireland)',
66
+ 'eu-west-2': 'EU (London)',
67
+ 'eu-west-3': 'EU (Paris)',
68
+ 'eu-central-1': 'EU (Frankfurt)',
69
+ 'eu-north-1': 'EU (Stockholm)',
70
+ 'ap-south-1': 'Asia Pacific (Mumbai)',
71
+ 'ap-southeast-1': 'Asia Pacific (Singapore)',
72
+ 'ap-southeast-2': 'Asia Pacific (Sydney)',
73
+ 'ap-northeast-1': 'Asia Pacific (Tokyo)',
74
+ 'ap-northeast-2': 'Asia Pacific (Seoul)',
75
+ };
76
+ return regionMap[region] || region;
77
+ }
78
+ }
79
+ exports.EC2Calculator = EC2Calculator;
80
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRUMyQ2FsY3VsYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wcmljaW5nL2NhbGN1bGF0b3JzL0VDMkNhbGN1bGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBR0EsTUFBYSxhQUFhO0lBQ3hCLFFBQVEsQ0FBQyxZQUFvQjtRQUMzQixPQUFPLFlBQVksS0FBSyxvQkFBb0IsQ0FBQztJQUMvQyxDQUFDO0lBRUQsS0FBSyxDQUFDLGFBQWEsQ0FDakIsUUFBd0IsRUFDeEIsTUFBYyxFQUNkLGFBQTRCO1FBRTVCLE1BQU0sWUFBWSxHQUFHLFFBQVEsQ0FBQyxVQUFVLENBQUMsWUFBc0IsQ0FBQztRQUVoRSxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDbEIsT0FBTztnQkFDTCxNQUFNLEVBQUUsQ0FBQztnQkFDVCxRQUFRLEVBQUUsS0FBSztnQkFDZixVQUFVLEVBQUUsU0FBUztnQkFDckIsV0FBVyxFQUFFLENBQUMsNkJBQTZCLENBQUM7YUFDN0MsQ0FBQztRQUNKLENBQUM7UUFFRCxJQUFJLENBQUM7WUFDSCxNQUFNLFVBQVUsR0FBRyxNQUFNLGFBQWEsQ0FBQyxRQUFRLENBQUM7Z0JBQzlDLFdBQVcsRUFBRSxXQUFXO2dCQUN4QixNQUFNLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUM7Z0JBQ3BDLE9BQU8sRUFBRTtvQkFDUCxFQUFFLEtBQUssRUFBRSxjQUFjLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRTtvQkFDOUMsRUFBRSxLQUFLLEVBQUUsaUJBQWlCLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRTtvQkFDNUMsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUU7b0JBQ3JDLEVBQUUsS0FBSyxFQUFFLGdCQUFnQixFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUU7b0JBQ3hDLEVBQUUsS0FBSyxFQUFFLGdCQUFnQixFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUU7aUJBQzNDO2FBQ0YsQ0FBQyxDQUFDO1lBRUgsSUFBSSxVQUFVLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQ3hCLE9BQU87b0JBQ0wsTUFBTSxFQUFFLENBQUM7b0JBQ1QsUUFBUSxFQUFFLEtBQUs7b0JBQ2YsVUFBVSxFQUFFLFNBQVM7b0JBQ3JCLFdBQVcsRUFBRSxDQUFDLGdEQUFnRCxZQUFZLGNBQWMsTUFBTSxFQUFFLENBQUM7aUJBQ2xHLENBQUM7WUFDSixDQUFDO1lBRUQsTUFBTSxZQUFZLEdBQUcsR0FBRyxDQUFDO1lBQ3pCLE1BQU0sV0FBVyxHQUFHLFVBQVUsR0FBRyxZQUFZLENBQUM7WUFFOUMsT0FBTztnQkFDTCxNQUFNLEVBQUUsV0FBVztnQkFDbkIsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsVUFBVSxFQUFFLE1BQU07Z0JBQ2xCLFdBQVcsRUFBRTtvQkFDWCxXQUFXLFlBQVksbUNBQW1DO29CQUMxRCxxREFBcUQ7aUJBQ3REO2FBQ0YsQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsT0FBTztnQkFDTCxNQUFNLEVBQUUsQ0FBQztnQkFDVCxRQUFRLEVBQUUsS0FBSztnQkFDZixVQUFVLEVBQUUsU0FBUztnQkFDckIsV0FBVyxFQUFFLENBQUMsNEJBQTRCLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO2FBQ3BHLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVPLGVBQWUsQ0FBQyxNQUFjO1FBQ3BDLE1BQU0sU0FBUyxHQUEyQjtZQUN4QyxXQUFXLEVBQUUsdUJBQXVCO1lBQ3BDLFdBQVcsRUFBRSxnQkFBZ0I7WUFDN0IsV0FBVyxFQUFFLHlCQUF5QjtZQUN0QyxXQUFXLEVBQUUsa0JBQWtCO1lBQy9CLFdBQVcsRUFBRSxjQUFjO1lBQzNCLFdBQVcsRUFBRSxhQUFhO1lBQzFCLFdBQVcsRUFBRSxZQUFZO1lBQ3pCLGNBQWMsRUFBRSxnQkFBZ0I7WUFDaEMsWUFBWSxFQUFFLGdCQUFnQjtZQUM5QixZQUFZLEVBQUUsdUJBQXVCO1lBQ3JDLGdCQUFnQixFQUFFLDBCQUEwQjtZQUM1QyxnQkFBZ0IsRUFBRSx1QkFBdUI7WUFDekMsZ0JBQWdCLEVBQUUsc0JBQXNCO1lBQ3hDLGdCQUFnQixFQUFFLHNCQUFzQjtTQUN6QyxDQUFDO1FBRUYsT0FBTyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksTUFBTSxDQUFDO0lBQ3JDLENBQUM7Q0FDRjtBQXJGRCxzQ0FxRkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXNvdXJjZVdpdGhJZCB9IGZyb20gJy4uLy4uL2RpZmYvdHlwZXMnO1xuaW1wb3J0IHsgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciwgTW9udGhseUNvc3QsIFByaWNpbmdDbGllbnQgfSBmcm9tICcuLi90eXBlcyc7XG5cbmV4cG9ydCBjbGFzcyBFQzJDYWxjdWxhdG9yIGltcGxlbWVudHMgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciB7XG4gIHN1cHBvcnRzKHJlc291cmNlVHlwZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHJlc291cmNlVHlwZSA9PT0gJ0FXUzo6RUMyOjpJbnN0YW5jZSc7XG4gIH1cblxuICBhc3luYyBjYWxjdWxhdGVDb3N0KFxuICAgIHJlc291cmNlOiBSZXNvdXJjZVdpdGhJZCxcbiAgICByZWdpb246IHN0cmluZyxcbiAgICBwcmljaW5nQ2xpZW50OiBQcmljaW5nQ2xpZW50LFxuICApOiBQcm9taXNlPE1vbnRobHlDb3N0PiB7XG4gICAgY29uc3QgaW5zdGFuY2VUeXBlID0gcmVzb3VyY2UucHJvcGVydGllcy5JbnN0YW5jZVR5cGUgYXMgc3RyaW5nO1xuXG4gICAgaWYgKCFpbnN0YW5jZVR5cGUpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAndW5rbm93bicsXG4gICAgICAgIGFzc3VtcHRpb25zOiBbJ0luc3RhbmNlIHR5cGUgbm90IHNwZWNpZmllZCddLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgaG91cmx5UmF0ZSA9IGF3YWl0IHByaWNpbmdDbGllbnQuZ2V0UHJpY2Uoe1xuICAgICAgICBzZXJ2aWNlQ29kZTogJ0FtYXpvbkVDMicsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW1xuICAgICAgICAgIHsgZmllbGQ6ICdpbnN0YW5jZVR5cGUnLCB2YWx1ZTogaW5zdGFuY2VUeXBlIH0sXG4gICAgICAgICAgeyBmaWVsZDogJ29wZXJhdGluZ1N5c3RlbScsIHZhbHVlOiAnTGludXgnIH0sXG4gICAgICAgICAgeyBmaWVsZDogJ3RlbmFuY3knLCB2YWx1ZTogJ1NoYXJlZCcgfSxcbiAgICAgICAgICB7IGZpZWxkOiAncHJlSW5zdGFsbGVkU3cnLCB2YWx1ZTogJ05BJyB9LFxuICAgICAgICAgIHsgZmllbGQ6ICdjYXBhY2l0eXN0YXR1cycsIHZhbHVlOiAnVXNlZCcgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoaG91cmx5UmF0ZSA9PT0gbnVsbCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgICAgY29uZmlkZW5jZTogJ3Vua25vd24nLFxuICAgICAgICAgIGFzc3VtcHRpb25zOiBbYFByaWNpbmcgZGF0YSBub3QgYXZhaWxhYmxlIGZvciBpbnN0YW5jZSB0eXBlICR7aW5zdGFuY2VUeXBlfSBpbiByZWdpb24gJHtyZWdpb259YF0sXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG1vbnRobHlIb3VycyA9IDczMDtcbiAgICAgIGNvbnN0IG1vbnRobHlDb3N0ID0gaG91cmx5UmF0ZSAqIG1vbnRobHlIb3VycztcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiBtb250aGx5Q29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnaGlnaCcsXG4gICAgICAgIGFzc3VtcHRpb25zOiBbXG4gICAgICAgICAgYEFzc3VtZXMgJHttb250aGx5SG91cnN9IGhvdXJzIHBlciBtb250aCAoMjQvNyBvcGVyYXRpb24pYCxcbiAgICAgICAgICAnQXNzdW1lcyBMaW51eCBPUywgc2hhcmVkIHRlbmFuY3ksIG9uLWRlbWFuZCBwcmljaW5nJyxcbiAgICAgICAgXSxcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAndW5rbm93bicsXG4gICAgICAgIGFzc3VtcHRpb25zOiBbYEZhaWxlZCB0byBmZXRjaCBwcmljaW5nOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gXSxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBub3JtYWxpemVSZWdpb24ocmVnaW9uOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHJlZ2lvbk1hcDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICAgICd1cy1lYXN0LTEnOiAnVVMgRWFzdCAoTi4gVmlyZ2luaWEpJyxcbiAgICAgICd1cy1lYXN0LTInOiAnVVMgRWFzdCAoT2hpbyknLFxuICAgICAgJ3VzLXdlc3QtMSc6ICdVUyBXZXN0IChOLiBDYWxpZm9ybmlhKScsXG4gICAgICAndXMtd2VzdC0yJzogJ1VTIFdlc3QgKE9yZWdvbiknLFxuICAgICAgJ2V1LXdlc3QtMSc6ICdFVSAoSXJlbGFuZCknLFxuICAgICAgJ2V1LXdlc3QtMic6ICdFVSAoTG9uZG9uKScsXG4gICAgICAnZXUtd2VzdC0zJzogJ0VVIChQYXJpcyknLFxuICAgICAgJ2V1LWNlbnRyYWwtMSc6ICdFVSAoRnJhbmtmdXJ0KScsXG4gICAgICAnZXUtbm9ydGgtMSc6ICdFVSAoU3RvY2tob2xtKScsXG4gICAgICAnYXAtc291dGgtMSc6ICdBc2lhIFBhY2lmaWMgKE11bWJhaSknLFxuICAgICAgJ2FwLXNvdXRoZWFzdC0xJzogJ0FzaWEgUGFjaWZpYyAoU2luZ2Fwb3JlKScsXG4gICAgICAnYXAtc291dGhlYXN0LTInOiAnQXNpYSBQYWNpZmljIChTeWRuZXkpJyxcbiAgICAgICdhcC1ub3J0aGVhc3QtMSc6ICdBc2lhIFBhY2lmaWMgKFRva3lvKScsXG4gICAgICAnYXAtbm9ydGhlYXN0LTInOiAnQXNpYSBQYWNpZmljIChTZW91bCknLFxuICAgIH07XG5cbiAgICByZXR1cm4gcmVnaW9uTWFwW3JlZ2lvbl0gfHwgcmVnaW9uO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,9 @@
1
+ import { ResourceWithId } from '../../diff/types';
2
+ import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
3
+ export declare class ECSCalculator implements ResourceCostCalculator {
4
+ supports(resourceType: string): boolean;
5
+ calculateCost(resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
6
+ private calculateFargateCost;
7
+ private calculateEC2Cost;
8
+ private normalizeRegion;
9
+ }
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ECSCalculator = void 0;
4
+ class ECSCalculator {
5
+ supports(resourceType) {
6
+ return resourceType === 'AWS::ECS::Service';
7
+ }
8
+ async calculateCost(resource, region, pricingClient) {
9
+ const desiredCount = resource.properties.DesiredCount || 1;
10
+ const launchType = resource.properties.LaunchType || 'FARGATE';
11
+ if (launchType === 'FARGATE') {
12
+ return this.calculateFargateCost(resource, desiredCount, region, pricingClient);
13
+ }
14
+ else if (launchType === 'EC2') {
15
+ return this.calculateEC2Cost(desiredCount);
16
+ }
17
+ else {
18
+ return {
19
+ amount: 0,
20
+ currency: 'USD',
21
+ confidence: 'unknown',
22
+ assumptions: [`Unsupported launch type: ${launchType}`],
23
+ };
24
+ }
25
+ }
26
+ async calculateFargateCost(_resource, desiredCount, region, pricingClient) {
27
+ try {
28
+ // Default assumptions for Fargate task
29
+ const assumedVCpu = 0.25; // 0.25 vCPU
30
+ const assumedMemoryGB = 0.5; // 0.5 GB
31
+ const vCpuCostPerHour = await pricingClient.getPrice({
32
+ serviceCode: 'AmazonECS',
33
+ region: this.normalizeRegion(region),
34
+ filters: [
35
+ { field: 'productFamily', value: 'Compute' },
36
+ { field: 'usagetype', value: `${region}-Fargate-vCPU-Hours:perCPU` },
37
+ ],
38
+ });
39
+ const memoryCostPerHour = await pricingClient.getPrice({
40
+ serviceCode: 'AmazonECS',
41
+ region: this.normalizeRegion(region),
42
+ filters: [
43
+ { field: 'productFamily', value: 'Compute' },
44
+ { field: 'usagetype', value: `${region}-Fargate-GB-Hours:perGB` },
45
+ ],
46
+ });
47
+ if (vCpuCostPerHour === null || memoryCostPerHour === null) {
48
+ return {
49
+ amount: 0,
50
+ currency: 'USD',
51
+ confidence: 'unknown',
52
+ assumptions: ['Pricing data not available for ECS Fargate'],
53
+ };
54
+ }
55
+ const hoursPerMonth = 730;
56
+ const vCpuCost = assumedVCpu * vCpuCostPerHour * hoursPerMonth * desiredCount;
57
+ const memoryCost = assumedMemoryGB * memoryCostPerHour * hoursPerMonth * desiredCount;
58
+ const monthlyCost = vCpuCost + memoryCost;
59
+ return {
60
+ amount: monthlyCost,
61
+ currency: 'USD',
62
+ confidence: 'medium',
63
+ assumptions: [
64
+ `${desiredCount} task(s) running`,
65
+ `Assumes ${assumedVCpu} vCPU per task`,
66
+ `Assumes ${assumedMemoryGB} GB memory per task`,
67
+ `Assumes ${hoursPerMonth} hours per month (24/7 operation)`,
68
+ 'Fargate launch type',
69
+ 'Does not include data transfer or storage costs',
70
+ ],
71
+ };
72
+ }
73
+ catch (error) {
74
+ return {
75
+ amount: 0,
76
+ currency: 'USD',
77
+ confidence: 'unknown',
78
+ assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
79
+ };
80
+ }
81
+ }
82
+ calculateEC2Cost(desiredCount) {
83
+ return {
84
+ amount: 0,
85
+ currency: 'USD',
86
+ confidence: 'low',
87
+ assumptions: [
88
+ `${desiredCount} task(s) running on EC2 launch type`,
89
+ 'EC2 launch type costs depend on underlying EC2 instances',
90
+ 'Refer to EC2 instance costs for actual pricing',
91
+ 'Does not include ECS task-specific costs (minimal for EC2 launch type)',
92
+ ],
93
+ };
94
+ }
95
+ normalizeRegion(region) {
96
+ const regionMap = {
97
+ 'us-east-1': 'US East (N. Virginia)',
98
+ 'us-east-2': 'US East (Ohio)',
99
+ 'us-west-1': 'US West (N. California)',
100
+ 'us-west-2': 'US West (Oregon)',
101
+ 'eu-west-1': 'EU (Ireland)',
102
+ 'eu-west-2': 'EU (London)',
103
+ 'eu-west-3': 'EU (Paris)',
104
+ 'eu-central-1': 'EU (Frankfurt)',
105
+ 'eu-north-1': 'EU (Stockholm)',
106
+ 'ap-south-1': 'Asia Pacific (Mumbai)',
107
+ 'ap-southeast-1': 'Asia Pacific (Singapore)',
108
+ 'ap-southeast-2': 'Asia Pacific (Sydney)',
109
+ 'ap-northeast-1': 'Asia Pacific (Tokyo)',
110
+ 'ap-northeast-2': 'Asia Pacific (Seoul)',
111
+ };
112
+ return regionMap[region] || region;
113
+ }
114
+ }
115
+ exports.ECSCalculator = ECSCalculator;
116
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRUNTQ2FsY3VsYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wcmljaW5nL2NhbGN1bGF0b3JzL0VDU0NhbGN1bGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBR0EsTUFBYSxhQUFhO0lBQ3hCLFFBQVEsQ0FBQyxZQUFvQjtRQUMzQixPQUFPLFlBQVksS0FBSyxtQkFBbUIsQ0FBQztJQUM5QyxDQUFDO0lBRUQsS0FBSyxDQUFDLGFBQWEsQ0FDakIsUUFBd0IsRUFDeEIsTUFBYyxFQUNkLGFBQTRCO1FBRTVCLE1BQU0sWUFBWSxHQUFJLFFBQVEsQ0FBQyxVQUFVLENBQUMsWUFBdUIsSUFBSSxDQUFDLENBQUM7UUFDdkUsTUFBTSxVQUFVLEdBQUksUUFBUSxDQUFDLFVBQVUsQ0FBQyxVQUFxQixJQUFJLFNBQVMsQ0FBQztRQUUzRSxJQUFJLFVBQVUsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUM3QixPQUFPLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxRQUFRLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxhQUFhLENBQUMsQ0FBQztRQUNsRixDQUFDO2FBQU0sSUFBSSxVQUFVLEtBQUssS0FBSyxFQUFFLENBQUM7WUFDaEMsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDN0MsQ0FBQzthQUFNLENBQUM7WUFDTixPQUFPO2dCQUNMLE1BQU0sRUFBRSxDQUFDO2dCQUNULFFBQVEsRUFBRSxLQUFLO2dCQUNmLFVBQVUsRUFBRSxTQUFTO2dCQUNyQixXQUFXLEVBQUUsQ0FBQyw0QkFBNEIsVUFBVSxFQUFFLENBQUM7YUFDeEQsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRU8sS0FBSyxDQUFDLG9CQUFvQixDQUNoQyxTQUF5QixFQUN6QixZQUFvQixFQUNwQixNQUFjLEVBQ2QsYUFBNEI7UUFFNUIsSUFBSSxDQUFDO1lBQ0gsdUNBQXVDO1lBQ3ZDLE1BQU0sV0FBVyxHQUFHLElB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QkFBa0I7WUFDL0IsV0FBVyxFQUFFLGNBQWM7WUFDM0IsV0FBVyxFQUFFLGFBQWE7WUFDMUIsV0FBVyxFQUFFLFlBQVk7WUFDekIsY0FBYyxFQUFFLGdCQUFnQjtZQUNoQyxZQUFZLEVBQUUsZ0JBQWdCO1lBQzlCLFlBQVksRUFBRSx1QkFBdUI7WUFDckMsZ0JBQWdCLEVBQUUsMEJBQTBCO1lBQzVDLGdCQUFnQixFQUFFLHVCQUF1QjtZQUN6QyxnQkFBZ0IsRUFBRSxzQkFBc0I7WUFDeEMsZ0JBQWdCLEVBQUUsc0JBQXNCO1NBQ3pDLENBQUM7UUFFRixPQUFPLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxNQUFNLENBQUM7SUFDckMsQ0FBQztDQUNGO0FBL0hELHNDQStIQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJlc291cmNlV2l0aElkIH0gZnJvbSAnLi4vLi4vZGlmZi90eXBlcyc7XG5pbXBvcnQgeyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yLCBNb250aGx5Q29zdCwgUHJpY2luZ0NsaWVudCB9IGZyb20gJy4uL3R5cGVzJztcblxuZXhwb3J0IGNsYXNzIEVDU0NhbGN1bGF0b3IgaW1wbGVtZW50cyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yIHtcbiAgc3VwcG9ydHMocmVzb3VyY2VUeXBlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gcmVzb3VyY2VUeXBlID09PSAnQVdTOjpFQ1M6OlNlcnZpY2UnO1xuICB9XG5cbiAgYXN5bmMgY2FsY3VsYXRlQ29zdChcbiAgICByZXNvdXJjZTogUmVzb3VyY2VXaXRoSWQsXG4gICAgcmVnaW9uOiBzdHJpbmcsXG4gICAgcHJpY2luZ0NsaWVudDogUHJpY2luZ0NsaWVudCxcbiAgKTogUHJvbWlzZTxNb250aGx5Q29zdD4ge1xuICAgIGNvbnN0IGRlc2lyZWRDb3VudCA9IChyZXNvdXJjZS5wcm9wZXJ0aWVzLkRlc2lyZWRDb3VudCBhcyBudW1iZXIpIHx8IDE7XG4gICAgY29uc3QgbGF1bmNoVHlwZSA9IChyZXNvdXJjZS5wcm9wZXJ0aWVzLkxhdW5jaFR5cGUgYXMgc3RyaW5nKSB8fCAnRkFSR0FURSc7XG5cbiAgICBpZiAobGF1bmNoVHlwZSA9PT0gJ0ZBUkdBVEUnKSB7XG4gICAgICByZXR1cm4gdGhpcy5jYWxjdWxhdGVGYXJnYXRlQ29zdChyZXNvdXJjZSwgZGVzaXJlZENvdW50LCByZWdpb24sIHByaWNpbmdDbGllbnQpO1xuICAgIH0gZWxzZSBpZiAobGF1bmNoVHlwZSA9PT0gJ0VDMicpIHtcbiAgICAgIHJldHVybiB0aGlzLmNhbGN1bGF0ZUVDMkNvc3QoZGVzaXJlZENvdW50KTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtgVW5zdXBwb3J0ZWQgbGF1bmNoIHR5cGU6ICR7bGF1bmNoVHlwZX1gXSxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjYWxjdWxhdGVGYXJnYXRlQ29zdChcbiAgICBfcmVzb3VyY2U6IFJlc291cmNlV2l0aElkLFxuICAgIGRlc2lyZWRDb3VudDogbnVtYmVyLFxuICAgIHJlZ2lvbjogc3RyaW5nLFxuICAgIHByaWNpbmdDbGllbnQ6IFByaWNpbmdDbGllbnQsXG4gICk6IFByb21pc2U8TW9udGhseUNvc3Q+IHtcbiAgICB0cnkge1xuICAgICAgLy8gRGVmYXVsdCBhc3N1bXB0aW9ucyBmb3IgRmFyZ2F0ZSB0YXNrXG4gICAgICBjb25zdCBhc3N1bWVkVkNwdSA9IDAuMjU7IC8vIDAuMjUgdkNQVVxuICAgICAgY29uc3QgYXNzdW1lZE1lbW9yeUdCID0gMC41OyAvLyAwLjUgR0JcblxuICAgICAgY29uc3QgdkNwdUNvc3RQZXJIb3VyID0gYXdhaXQgcHJpY2luZ0NsaWVudC5nZXRQcmljZSh7XG4gICAgICAgIHNlcnZpY2VDb2RlOiAnQW1hem9uRUNTJyxcbiAgICAgICAgcmVnaW9uOiB0aGlzLm5vcm1hbGl6ZVJlZ2lvbihyZWdpb24pLFxuICAgICAgICBmaWx0ZXJzOiBbXG4gICAgICAgICAgeyBmaWVsZDogJ3Byb2R1Y3RGYW1pbHknLCB2YWx1ZTogJ0NvbXB1dGUnIH0sXG4gICAgICAgICAgeyBmaWVsZDogJ3VzYWdldHlwZScsIHZhbHVlOiBgJHtyZWdpb259LUZhcmdhdGUtdkNQVS1Ib3VyczpwZXJDUFVgIH0sXG4gICAgICAgIF0sXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgbWVtb3J5Q29zdFBlckhvdXIgPSBhd2FpdCBwcmljaW5nQ2xpZW50LmdldFByaWNlKHtcbiAgICAgICAgc2VydmljZUNvZGU6ICdBbWF6b25FQ1MnLFxuICAgICAgICByZWdpb246IHRoaXMubm9ybWFsaXplUmVnaW9uKHJlZ2lvbiksXG4gICAgICAgIGZpbHRlcnM6IFtcbiAgICAgICAgICB7IGZpZWxkOiAncHJvZHVjdEZhbWlseScsIHZhbHVlOiAnQ29tcHV0ZScgfSxcbiAgICAgICAgICB7IGZpZWxkOiAndXNhZ2V0eXBlJywgdmFsdWU6IGAke3JlZ2lvbn0tRmFyZ2F0ZS1HQi1Ib3VyczpwZXJHQmAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAodkNwdUNvc3RQZXJIb3VyID09PSBudWxsIHx8IG1lbW9yeUNvc3RQZXJIb3VyID09PSBudWxsKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgICAgICBjb25maWRlbmNlOiAndW5rbm93bicsXG4gICAgICAgICAgYXNzdW1wdGlvbnM6IFsnUHJpY2luZyBkYXRhIG5vdCBhdmFpbGFibGUgZm9yIEVDUyBGYXJnYXRlJ10sXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhvdXJzUGVyTW9udGggPSA3MzA7XG4gICAgICBjb25zdCB2Q3B1Q29zdCA9IGFzc3VtZWRWQ3B1ICogdkNwdUNvc3RQZXJIb3VyICogaG91cnNQZXJNb250aCAqIGRlc2lyZWRDb3VudDtcbiAgICAgIGNvbnN0IG1lbW9yeUNvc3QgPSBhc3N1bWVkTWVtb3J5R0IgKiBtZW1vcnlDb3N0UGVySG91ciAqIGhvdXJzUGVyTW9udGggKiBkZXNpcmVkQ291bnQ7XG4gICAgICBjb25zdCBtb250aGx5Q29zdCA9IHZDcHVDb3N0ICsgbWVtb3J5Q29zdDtcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiBtb250aGx5Q29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnbWVkaXVtJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtcbiAgICAgICAgICBgJHtkZXNpcmVkQ291bnR9IHRhc2socykgcnVubmluZ2AsXG4gICAgICAgICAgYEFzc3VtZXMgJHthc3N1bWVkVkNwdX0gdkNQVSBwZXIgdGFza2AsXG4gICAgICAgICAgYEFzc3VtZXMgJHthc3N1bWVkTWVtb3J5R0J9IEdCIG1lbW9yeSBwZXIgdGFza2AsXG4gICAgICAgICAgYEFzc3VtZXMgJHtob3Vyc1Blck1vbnRofSBob3VycyBwZXIgbW9udGggKDI0Lzcgb3BlcmF0aW9uKWAsXG4gICAgICAgICAgJ0ZhcmdhdGUgbGF1bmNoIHR5cGUnLFxuICAgICAgICAgICdEb2VzIG5vdCBpbmNsdWRlIGRhdGEgdHJhbnNmZXIgb3Igc3RvcmFnZSBjb3N0cycsXG4gICAgICAgIF0sXG4gICAgICB9O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgICAgY29uZmlkZW5jZTogJ3Vua25vd24nLFxuICAgICAgICBhc3N1bXB0aW9uczogW2BGYWlsZWQgdG8gZmV0Y2ggcHJpY2luZzogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YF0sXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgY2FsY3VsYXRlRUMyQ29zdChkZXNpcmVkQ291bnQ6IG51bWJlcik6IE1vbnRobHlDb3N0IHtcbiAgICByZXR1cm4ge1xuICAgICAgYW1vdW50OiAwLFxuICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgY29uZmlkZW5jZTogJ2xvdycsXG4gICAgICBhc3N1bXB0aW9uczogW1xuICAgICAgICBgJHtkZXNpcmVkQ291bnR9IHRhc2socykgcnVubmluZyBvbiBFQzIgbGF1bmNoIHR5cGVgLFxuICAgICAgICAnRUMyIGxhdW5jaCB0eXBlIGNvc3RzIGRlcGVuZCBvbiB1bmRlcmx5aW5nIEVDMiBpbnN0YW5jZXMnLFxuICAgICAgICAnUmVmZXIgdG8gRUMyIGluc3RhbmNlIGNvc3RzIGZvciBhY3R1YWwgcHJpY2luZycsXG4gICAgICAgICdEb2VzIG5vdCBpbmNsdWRlIEVDUyB0YXNrLXNwZWNpZmljIGNvc3RzIChtaW5pbWFsIGZvciBFQzIgbGF1bmNoIHR5cGUpJyxcbiAgICAgIF0sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgbm9ybWFsaXplUmVnaW9uKHJlZ2lvbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCByZWdpb25NYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICAndXMtZWFzdC0xJzogJ1VTIEVhc3QgKE4uIFZpcmdpbmlhKScsXG4gICAgICAndXMtZWFzdC0yJzogJ1VTIEVhc3QgKE9oaW8pJyxcbiAgICAgICd1cy13ZXN0LTEnOiAnVVMgV2VzdCAoTi4gQ2FsaWZvcm5pYSknLFxuICAgICAgJ3VzLXdlc3QtMic6ICdVUyBXZXN0IChPcmVnb24pJyxcbiAgICAgICdldS13ZXN0LTEnOiAnRVUgKElyZWxhbmQpJyxcbiAgICAgICdldS13ZXN0LTInOiAnRVUgKExvbmRvbiknLFxuICAgICAgJ2V1LXdlc3QtMyc6ICdFVSAoUGFyaXMpJyxcbiAgICAgICdldS1jZW50cmFsLTEnOiAnRVUgKEZyYW5rZnVydCknLFxuICAgICAgJ2V1LW5vcnRoLTEnOiAnRVUgKFN0b2NraG9sbSknLFxuICAgICAgJ2FwLXNvdXRoLTEnOiAnQXNpYSBQYWNpZmljIChNdW1iYWkpJyxcbiAgICAgICdhcC1zb3V0aGVhc3QtMSc6ICdBc2lhIFBhY2lmaWMgKFNpbmdhcG9yZSknLFxuICAgICAgJ2FwLXNvdXRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU3lkbmV5KScsXG4gICAgICAnYXAtbm9ydGhlYXN0LTEnOiAnQXNpYSBQYWNpZmljIChUb2t5byknLFxuICAgICAgJ2FwLW5vcnRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU2VvdWwpJyxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHJlZ2lvbk1hcFtyZWdpb25dIHx8IHJlZ2lvbjtcbiAgfVxufVxuIl19
@@ -0,0 +1,8 @@
1
+ import { ResourceWithId } from '../../diff/types';
2
+ import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
3
+ export declare class ElastiCacheCalculator implements ResourceCostCalculator {
4
+ supports(resourceType: string): boolean;
5
+ calculateCost(resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
6
+ private normalizeEngine;
7
+ private normalizeRegion;
8
+ }
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ElastiCacheCalculator = void 0;
4
+ class ElastiCacheCalculator {
5
+ supports(resourceType) {
6
+ return resourceType === 'AWS::ElastiCache::CacheCluster';
7
+ }
8
+ async calculateCost(resource, region, pricingClient) {
9
+ const cacheNodeType = resource.properties.CacheNodeType;
10
+ const engine = resource.properties.Engine;
11
+ const numCacheNodes = resource.properties.NumCacheNodes || 1;
12
+ const azMode = resource.properties.AZMode;
13
+ if (!cacheNodeType || !engine) {
14
+ return {
15
+ amount: 0,
16
+ currency: 'USD',
17
+ confidence: 'unknown',
18
+ assumptions: ['Cache node type or engine not specified'],
19
+ };
20
+ }
21
+ try {
22
+ // Query AWS Pricing API for node hourly rates
23
+ const hourlyRate = await pricingClient.getPrice({
24
+ serviceCode: 'AmazonElastiCache',
25
+ region: this.normalizeRegion(region),
26
+ filters: [
27
+ { field: 'instanceType', value: cacheNodeType },
28
+ { field: 'cacheEngine', value: this.normalizeEngine(engine) },
29
+ ],
30
+ });
31
+ if (hourlyRate === null) {
32
+ return {
33
+ amount: 0,
34
+ currency: 'USD',
35
+ confidence: 'unknown',
36
+ assumptions: [
37
+ `Pricing data not available for node type ${cacheNodeType} with engine ${engine} in region ${region}`,
38
+ ],
39
+ };
40
+ }
41
+ const monthlyHours = 730;
42
+ const perNodeCost = hourlyRate * monthlyHours;
43
+ let totalCost = perNodeCost * numCacheNodes;
44
+ const assumptions = [
45
+ `Assumes ${monthlyHours} hours per month (24/7 operation)`,
46
+ `Node type: ${cacheNodeType}`,
47
+ `Engine: ${engine}`,
48
+ `Number of cache nodes: ${numCacheNodes}`,
49
+ `Per-node monthly cost: $${perNodeCost.toFixed(2)}`,
50
+ ];
51
+ // Account for multi-AZ replica costs when configured
52
+ if (azMode === 'cross-az') {
53
+ // Multi-AZ adds replica nodes (typically doubles the cost)
54
+ totalCost *= 2;
55
+ assumptions.push('Multi-AZ deployment with replica nodes (cost doubled)');
56
+ }
57
+ else {
58
+ assumptions.push('Single-AZ deployment');
59
+ }
60
+ return {
61
+ amount: totalCost,
62
+ currency: 'USD',
63
+ confidence: 'high',
64
+ assumptions,
65
+ };
66
+ }
67
+ catch (error) {
68
+ return {
69
+ amount: 0,
70
+ currency: 'USD',
71
+ confidence: 'unknown',
72
+ assumptions: [
73
+ `Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`,
74
+ ],
75
+ };
76
+ }
77
+ }
78
+ normalizeEngine(engine) {
79
+ const engineMap = {
80
+ redis: 'Redis',
81
+ memcached: 'Memcached',
82
+ };
83
+ return engineMap[engine.toLowerCase()] || engine;
84
+ }
85
+ normalizeRegion(region) {
86
+ const regionMap = {
87
+ 'us-east-1': 'US East (N. Virginia)',
88
+ 'us-east-2': 'US East (Ohio)',
89
+ 'us-west-1': 'US West (N. California)',
90
+ 'us-west-2': 'US West (Oregon)',
91
+ 'eu-west-1': 'EU (Ireland)',
92
+ 'eu-west-2': 'EU (London)',
93
+ 'eu-west-3': 'EU (Paris)',
94
+ 'eu-central-1': 'EU (Frankfurt)',
95
+ 'eu-north-1': 'EU (Stockholm)',
96
+ 'ap-south-1': 'Asia Pacific (Mumbai)',
97
+ 'ap-southeast-1': 'Asia Pacific (Singapore)',
98
+ 'ap-southeast-2': 'Asia Pacific (Sydney)',
99
+ 'ap-northeast-1': 'Asia Pacific (Tokyo)',
100
+ 'ap-northeast-2': 'Asia Pacific (Seoul)',
101
+ };
102
+ return regionMap[region] || region;
103
+ }
104
+ }
105
+ exports.ElastiCacheCalculator = ElastiCacheCalculator;
106
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRWxhc3RpQ2FjaGVDYWxjdWxhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ByaWNpbmcvY2FsY3VsYXRvcnMvRWxhc3RpQ2FjaGVDYWxjdWxhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUdBLE1BQWEscUJBQXFCO0lBQ2hDLFFBQVEsQ0FBQyxZQUFvQjtRQUMzQixPQUFPLFlBQVksS0FBSyxnQ0FBZ0MsQ0FBQztJQUMzRCxDQUFDO0lBRUQsS0FBSyxDQUFDLGFBQWEsQ0FDakIsUUFBd0IsRUFDeEIsTUFBYyxFQUNkLGFBQTRCO1FBRTVCLE1BQU0sYUFBYSxHQUFHLFFBQVEsQ0FBQyxVQUFVLENBQUMsYUFBdUIsQ0FBQztRQUNsRSxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsVUFBVSxDQUFDLE1BQWdCLENBQUM7UUFDcEQsTUFBTSxhQUFhLEdBQUksUUFBUSxDQUFDLFVBQVUsQ0FBQyxhQUF3QixJQUFJLENBQUMsQ0FBQztRQUN6RSxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsVUFBVSxDQUFDLE1BQWdCLENBQUM7UUFFcEQsSUFBSSxDQUFDLGFBQWEsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQzlCLE9BQU87Z0JBQ0wsTUFBTSxFQUFFLENBQUM7Z0JBQ1QsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsVUFBVSxFQUFFLFNBQVM7Z0JBQ3JCLFdBQVcsRUFBRSxDQUFDLHlDQUF5QyxDQUFDO2FBQ3pELENBQUM7UUFDSixDQUFDO1FBRUQsSUFBSSxDQUFDO1lBQ0gsOENBQThDO1lBQzlDLE1BQU0sVUFBVSxHQUFHLE1BQU0sYUFBYSxDQUFDLFFBQVEsQ0FBQztnQkFDOUMsV0FBVyxFQUFFLG1CQUFtQjtnQkFDaEMsTUFBTSxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDO2dCQUNwQyxPQUFPLEVBQUU7b0JBQ1AsRUFBRSxLQUFLLEVBQUUsY0FBYyxFQUFFLEtBQUssRUFBRSxhQUFhLEVB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dXJjZVdpdGhJZCB9IGZyb20gJy4uLy4uL2RpZmYvdHlwZXMnO1xuaW1wb3J0IHsgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciwgTW9udGhseUNvc3QsIFByaWNpbmdDbGllbnQgfSBmcm9tICcuLi90eXBlcyc7XG5cbmV4cG9ydCBjbGFzcyBFbGFzdGlDYWNoZUNhbGN1bGF0b3IgaW1wbGVtZW50cyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yIHtcbiAgc3VwcG9ydHMocmVzb3VyY2VUeXBlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gcmVzb3VyY2VUeXBlID09PSAnQVdTOjpFbGFzdGlDYWNoZTo6Q2FjaGVDbHVzdGVyJztcbiAgfVxuXG4gIGFzeW5jIGNhbGN1bGF0ZUNvc3QoXG4gICAgcmVzb3VyY2U6IFJlc291cmNlV2l0aElkLFxuICAgIHJlZ2lvbjogc3RyaW5nLFxuICAgIHByaWNpbmdDbGllbnQ6IFByaWNpbmdDbGllbnQsXG4gICk6IFByb21pc2U8TW9udGhseUNvc3Q+IHtcbiAgICBjb25zdCBjYWNoZU5vZGVUeXBlID0gcmVzb3VyY2UucHJvcGVydGllcy5DYWNoZU5vZGVUeXBlIGFzIHN0cmluZztcbiAgICBjb25zdCBlbmdpbmUgPSByZXNvdXJjZS5wcm9wZXJ0aWVzLkVuZ2luZSBhcyBzdHJpbmc7XG4gICAgY29uc3QgbnVtQ2FjaGVOb2RlcyA9IChyZXNvdXJjZS5wcm9wZXJ0aWVzLk51bUNhY2hlTm9kZXMgYXMgbnVtYmVyKSB8fCAxO1xuICAgIGNvbnN0IGF6TW9kZSA9IHJlc291cmNlLnByb3BlcnRpZXMuQVpNb2RlIGFzIHN0cmluZztcblxuICAgIGlmICghY2FjaGVOb2RlVHlwZSB8fCAhZW5naW5lKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgICAgY29uZmlkZW5jZTogJ3Vua25vd24nLFxuICAgICAgICBhc3N1bXB0aW9uczogWydDYWNoZSBub2RlIHR5cGUgb3IgZW5naW5lIG5vdCBzcGVjaWZpZWQnXSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIC8vIFF1ZXJ5IEFXUyBQcmljaW5nIEFQSSBmb3Igbm9kZSBob3VybHkgcmF0ZXNcbiAgICAgIGNvbnN0IGhvdXJseVJhdGUgPSBhd2FpdCBwcmljaW5nQ2xpZW50LmdldFByaWNlKHtcbiAgICAgICAgc2VydmljZUNvZGU6ICdBbWF6b25FbGFzdGlDYWNoZScsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW1xuICAgICAgICAgIHsgZmllbGQ6ICdpbnN0YW5jZVR5cGUnLCB2YWx1ZTogY2FjaGVOb2RlVHlwZSB9LFxuICAgICAgICAgIHsgZmllbGQ6ICdjYWNoZUVuZ2luZScsIHZhbHVlOiB0aGlzLm5vcm1hbGl6ZUVuZ2luZShlbmdpbmUpIH0sXG4gICAgICAgIF0sXG4gICAgICB9KTtcblxuICAgICAgaWYgKGhvdXJseVJhdGUgPT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgICBhc3N1bXB0aW9uczogW1xuICAgICAgICAgICAgYFByaWNpbmcgZGF0YSBub3QgYXZhaWxhYmxlIGZvciBub2RlIHR5cGUgJHtjYWNoZU5vZGVUeXBlfSB3aXRoIGVuZ2luZSAke2VuZ2luZX0gaW4gcmVnaW9uICR7cmVnaW9ufWAsXG4gICAgICAgICAgXSxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbW9udGhseUhvdXJzID0gNzMwO1xuICAgICAgY29uc3QgcGVyTm9kZUNvc3QgPSBob3VybHlSYXRlICogbW9udGhseUhvdXJzO1xuICAgICAgbGV0IHRvdGFsQ29zdCA9IHBlck5vZGVDb3N0ICogbnVtQ2FjaGVOb2RlcztcblxuICAgICAgY29uc3QgYXNzdW1wdGlvbnMgPSBbXG4gICAgICAgIGBBc3N1bWVzICR7bW9udGhseUhvdXJzfSBob3VycyBwZXIgbW9udGggKDI0Lzcgb3BlcmF0aW9uKWAsXG4gICAgICAgIGBOb2RlIHR5cGU6ICR7Y2FjaGVOb2RlVHlwZX1gLFxuICAgICAgICBgRW5naW5lOiAke2VuZ2luZX1gLFxuICAgICAgICBgTnVtYmVyIG9mIGNhY2hlIG5vZGVzOiAke251bUNhY2hlTm9kZXN9YCxcbiAgICAgICAgYFBlci1ub2RlIG1vbnRobHkgY29zdDogJCR7cGVyTm9kZUNvc3QudG9GaXhlZCgyKX1gLFxuICAgICAgXTtcblxuICAgICAgLy8gQWNjb3VudCBmb3IgbXVsdGktQVogcmVwbGljYSBjb3N0cyB3aGVuIGNvbmZpZ3VyZWRcbiAgICAgIGlmIChhek1vZGUgPT09ICdjcm9zcy1heicpIHtcbiAgICAgICAgLy8gTXVsdGktQVogYWRkcyByZXBsaWNhIG5vZGVzICh0eXBpY2FsbHkgZG91YmxlcyB0aGUgY29zdClcbiAgICAgICAgdG90YWxDb3N0ICo9IDI7XG4gICAgICAgIGFzc3VtcHRpb25zLnB1c2goJ011bHRpLUFaIGRlcGxveW1lbnQgd2l0aCByZXBsaWNhIG5vZGVzIChjb3N0IGRvdWJsZWQpJyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBhc3N1bXB0aW9ucy5wdXNoKCdTaW5nbGUtQVogZGVwbG95bWVudCcpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IHRvdGFsQ29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnaGlnaCcsXG4gICAgICAgIGFzc3VtcHRpb25zLFxuICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtcbiAgICAgICAgICBgRmFpbGVkIHRvIGZldGNoIHByaWNpbmc6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWAsXG4gICAgICAgIF0sXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgbm9ybWFsaXplRW5naW5lKGVuZ2luZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBlbmdpbmVNYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICByZWRpczogJ1JlZGlzJyxcbiAgICAgIG1lbWNhY2hlZDogJ01lbWNhY2hlZCcsXG4gICAgfTtcblxuICAgIHJldHVybiBlbmdpbmVNYXBbZW5naW5lLnRvTG93ZXJDYXNlKCldIHx8IGVuZ2luZTtcbiAgfVxuXG4gIHByaXZhdGUgbm9ybWFsaXplUmVnaW9uKHJlZ2lvbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCByZWdpb25NYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICAndXMtZWFzdC0xJzogJ1VTIEVhc3QgKE4uIFZpcmdpbmlhKScsXG4gICAgICAndXMtZWFzdC0yJzogJ1VTIEVhc3QgKE9oaW8pJyxcbiAgICAgICd1cy13ZXN0LTEnOiAnVVMgV2VzdCAoTi4gQ2FsaWZvcm5pYSknLFxuICAgICAgJ3VzLXdlc3QtMic6ICdVUyBXZXN0IChPcmVnb24pJyxcbiAgICAgICdldS13ZXN0LTEnOiAnRVUgKElyZWxhbmQpJyxcbiAgICAgICdldS13ZXN0LTInOiAnRVUgKExvbmRvbiknLFxuICAgICAgJ2V1LXdlc3QtMyc6ICdFVSAoUGFyaXMpJyxcbiAgICAgICdldS1jZW50cmFsLTEnOiAnRVUgKEZyYW5rZnVydCknLFxuICAgICAgJ2V1LW5vcnRoLTEnOiAnRVUgKFN0b2NraG9sbSknLFxuICAgICAgJ2FwLXNvdXRoLTEnOiAnQXNpYSBQYWNpZmljIChNdW1iYWkpJyxcbiAgICAgICdhcC1zb3V0aGVhc3QtMSc6ICdBc2lhIFBhY2lmaWMgKFNpbmdhcG9yZSknLFxuICAgICAgJ2FwLXNvdXRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU3lkbmV5KScsXG4gICAgICAnYXAtbm9ydGhlYXN0LTEnOiAnQXNpYSBQYWNpZmljIChUb2t5byknLFxuICAgICAgJ2FwLW5vcnRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU2VvdWwpJyxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHJlZ2lvbk1hcFtyZWdpb25dIHx8IHJlZ2lvbjtcbiAgfVxufVxuIl19
@@ -0,0 +1,13 @@
1
+ import { ResourceWithId } from '../../diff/types';
2
+ import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
3
+ export declare class LambdaCalculator implements ResourceCostCalculator {
4
+ private readonly customInvocationsPerMonth?;
5
+ private readonly customAverageDurationMs?;
6
+ private readonly DEFAULT_INVOCATIONS;
7
+ private readonly DEFAULT_DURATION_MS;
8
+ private readonly DEFAULT_MEMORY_MB;
9
+ constructor(customInvocationsPerMonth?: number | undefined, customAverageDurationMs?: number | undefined);
10
+ supports(resourceType: string): boolean;
11
+ calculateCost(resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
12
+ private normalizeRegion;
13
+ }
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LambdaCalculator = void 0;
4
+ class LambdaCalculator {
5
+ customInvocationsPerMonth;
6
+ customAverageDurationMs;
7
+ DEFAULT_INVOCATIONS = 1000000;
8
+ DEFAULT_DURATION_MS = 1000;
9
+ DEFAULT_MEMORY_MB = 128;
10
+ constructor(customInvocationsPerMonth, customAverageDurationMs) {
11
+ this.customInvocationsPerMonth = customInvocationsPerMonth;
12
+ this.customAverageDurationMs = customAverageDurationMs;
13
+ }
14
+ supports(resourceType) {
15
+ return resourceType === 'AWS::Lambda::Function';
16
+ }
17
+ async calculateCost(resource, region, pricingClient) {
18
+ const memorySize = resource.properties.MemorySize || this.DEFAULT_MEMORY_MB;
19
+ const invocations = this.customInvocationsPerMonth ?? this.DEFAULT_INVOCATIONS;
20
+ const durationMs = this.customAverageDurationMs ?? this.DEFAULT_DURATION_MS;
21
+ try {
22
+ const requestPrice = await pricingClient.getPrice({
23
+ serviceCode: 'AWSLambda',
24
+ region: this.normalizeRegion(region),
25
+ filters: [
26
+ { field: 'group', value: 'AWS-Lambda-Requests' },
27
+ ],
28
+ });
29
+ const computePrice = await pricingClient.getPrice({
30
+ serviceCode: 'AWSLambda',
31
+ region: this.normalizeRegion(region),
32
+ filters: [
33
+ { field: 'group', value: 'AWS-Lambda-Duration' },
34
+ ],
35
+ });
36
+ const assumptions = [
37
+ `Assumes ${invocations.toLocaleString()} invocations per month`,
38
+ `Assumes ${durationMs}ms average execution time`,
39
+ `Assumes ${memorySize}MB memory allocation`,
40
+ ];
41
+ if (this.customInvocationsPerMonth !== undefined) {
42
+ assumptions.push('Using custom invocation count assumption from configuration');
43
+ }
44
+ if (this.customAverageDurationMs !== undefined) {
45
+ assumptions.push('Using custom duration assumption from configuration');
46
+ }
47
+ if (requestPrice === null || computePrice === null) {
48
+ return {
49
+ amount: 0,
50
+ currency: 'USD',
51
+ confidence: 'unknown',
52
+ assumptions: [
53
+ `Pricing data not available for Lambda in region ${region}`,
54
+ ...assumptions,
55
+ ],
56
+ };
57
+ }
58
+ const requestCost = (invocations / 1000000) * requestPrice;
59
+ const gbSeconds = (memorySize / 1024) * (durationMs / 1000) * invocations;
60
+ const computeCost = gbSeconds * computePrice;
61
+ const totalCost = requestCost + computeCost;
62
+ return {
63
+ amount: totalCost,
64
+ currency: 'USD',
65
+ confidence: 'medium',
66
+ assumptions,
67
+ };
68
+ }
69
+ catch (error) {
70
+ const assumptions = [
71
+ `Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`,
72
+ `Would assume ${invocations.toLocaleString()} invocations per month`,
73
+ `Would assume ${durationMs}ms average execution time`,
74
+ `Would assume ${memorySize}MB memory allocation`,
75
+ ];
76
+ if (this.customInvocationsPerMonth !== undefined) {
77
+ assumptions.push('Using custom invocation count assumption from configuration');
78
+ }
79
+ if (this.customAverageDurationMs !== undefined) {
80
+ assumptions.push('Using custom duration assumption from configuration');
81
+ }
82
+ return {
83
+ amount: 0,
84
+ currency: 'USD',
85
+ confidence: 'unknown',
86
+ assumptions,
87
+ };
88
+ }
89
+ }
90
+ normalizeRegion(region) {
91
+ const regionMap = {
92
+ 'us-east-1': 'US East (N. Virginia)',
93
+ 'us-east-2': 'US East (Ohio)',
94
+ 'us-west-1': 'US West (N. California)',
95
+ 'us-west-2': 'US West (Oregon)',
96
+ 'eu-west-1': 'EU (Ireland)',
97
+ 'eu-west-2': 'EU (London)',
98
+ 'eu-west-3': 'EU (Paris)',
99
+ 'eu-central-1': 'EU (Frankfurt)',
100
+ 'eu-north-1': 'EU (Stockholm)',
101
+ 'ap-south-1': 'Asia Pacific (Mumbai)',
102
+ 'ap-southeast-1': 'Asia Pacific (Singapore)',
103
+ 'ap-southeast-2': 'Asia Pacific (Sydney)',
104
+ 'ap-northeast-1': 'Asia Pacific (Tokyo)',
105
+ 'ap-northeast-2': 'Asia Pacific (Seoul)',
106
+ };
107
+ return regionMap[region] || region;
108
+ }
109
+ }
110
+ exports.LambdaCalculator = LambdaCalculator;
111
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGFtYmRhQ2FsY3VsYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wcmljaW5nL2NhbGN1bGF0b3JzL0xhbWJkYUNhbGN1bGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBR0EsTUFBYSxnQkFBZ0I7SUFNUjtJQUNBO0lBTkYsbUJBQW1CLEdBQUcsT0FBTyxDQUFDO0lBQzlCLG1CQUFtQixHQUFHLElBQUksQ0FBQztJQUMzQixpQkFBaUIsR0FBRyxHQUFHLENBQUM7SUFFekMsWUFDbUIseUJBQWtDLEVBQ2xDLHVCQUFnQztRQURoQyw4QkFBeUIsR0FBekIseUJBQXlCLENBQVM7UUFDbEMsNEJBQXVCLEdBQXZCLHVCQUF1QixDQUFTO0lBQ2hELENBQUM7SUFFSixRQUFRLENBQUMsWUFBb0I7UUFDM0IsT0FBTyxZQUFZLEtBQUssdUJBQXVCLENBQUM7SUFDbEQsQ0FBQztJQUVELEtBQUssQ0FBQyxhQUFhLENBQ2pCLFFBQXdCLEVBQ3hCLE1BQWMsRUFDZCxhQUE0QjtRQUU1QixNQUFNLFVBQVUsR0FBSSxRQUFRLENBQUMsVUFBVSxDQUFDLFVBQXFCLElBQUksSUFBSSxDQUFDLGlCQUFpQixDQUFDO1FBQ3hGLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyx5QkFBeUIsSUFBSSxJQUFJLENBQUMsbUJBQW1CLENBQUM7UUFDL0UsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLHVCQUF1QixJQUFJLElBQUksQ0FBQyxtQkFBbUIsQ0FBQztRQUU1RSxJQUFJLENBQUM7WUFDSCxNQUFNLFlBQVksR0FBRyxNQUFNLGFBQWEsQ0FBQyxRQUFRLENBQUM7Z0JBQ2hELFdBQVcsRUFBRSxXQUFXO2dCQUN4QixNQUFNLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUM7Z0JBQ3BDLE9BQU8sRUFBRTtvQkFDUCxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLHFCQUFxQixFQUFFO2lCQUNqRDthQUNG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V0FBVyxFQUFFLGNBQWM7WUFDM0IsV0FBVyxFQUFFLGFBQWE7WUFDMUIsV0FBVyxFQUFFLFlBQVk7WUFDekIsY0FBYyxFQUFFLGdCQUFnQjtZQUNoQyxZQUFZLEVBQUUsZ0JBQWdCO1lBQzlCLFlBQVksRUFBRSx1QkFBdUI7WUFDckMsZ0JBQWdCLEVBQUUsMEJBQTBCO1lBQzVDLGdCQUFnQixFQUFFLHVCQUF1QjtZQUN6QyxnQkFBZ0IsRUFBRSxzQkFBc0I7WUFDeEMsZ0JBQWdCLEVBQUUsc0JBQXNCO1NBQ3pDLENBQUM7UUFFRixPQUFPLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxNQUFNLENBQUM7SUFDckMsQ0FBQztDQUNGO0FBMUhELDRDQTBIQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJlc291cmNlV2l0aElkIH0gZnJvbSAnLi4vLi4vZGlmZi90eXBlcyc7XG5pbXBvcnQgeyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yLCBNb250aGx5Q29zdCwgUHJpY2luZ0NsaWVudCB9IGZyb20gJy4uL3R5cGVzJztcblxuZXhwb3J0IGNsYXNzIExhbWJkYUNhbGN1bGF0b3IgaW1wbGVtZW50cyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yIHtcbiAgcHJpdmF0ZSByZWFkb25seSBERUZBVUxUX0lOVk9DQVRJT05TID0gMTAwMDAwMDtcbiAgcHJpdmF0ZSByZWFkb25seSBERUZBVUxUX0RVUkFUSU9OX01TID0gMTAwMDtcbiAgcHJpdmF0ZSByZWFkb25seSBERUZBVUxUX01FTU9SWV9NQiA9IDEyODtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IGN1c3RvbUludm9jYXRpb25zUGVyTW9udGg/OiBudW1iZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSBjdXN0b21BdmVyYWdlRHVyYXRpb25Ncz86IG51bWJlcixcbiAgKSB7fVxuXG4gIHN1cHBvcnRzKHJlc291cmNlVHlwZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHJlc291cmNlVHlwZSA9PT0gJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbic7XG4gIH1cblxuICBhc3luYyBjYWxjdWxhdGVDb3N0KFxuICAgIHJlc291cmNlOiBSZXNvdXJjZVdpdGhJZCxcbiAgICByZWdpb246IHN0cmluZyxcbiAgICBwcmljaW5nQ2xpZW50OiBQcmljaW5nQ2xpZW50LFxuICApOiBQcm9taXNlPE1vbnRobHlDb3N0PiB7XG4gICAgY29uc3QgbWVtb3J5U2l6ZSA9IChyZXNvdXJjZS5wcm9wZXJ0aWVzLk1lbW9yeVNpemUgYXMgbnVtYmVyKSB8fCB0aGlzLkRFRkFVTFRfTUVNT1JZX01CO1xuICAgIGNvbnN0IGludm9jYXRpb25zID0gdGhpcy5jdXN0b21JbnZvY2F0aW9uc1Blck1vbnRoID8/IHRoaXMuREVGQVVMVF9JTlZPQ0FUSU9OUztcbiAgICBjb25zdCBkdXJhdGlvbk1zID0gdGhpcy5jdXN0b21BdmVyYWdlRHVyYXRpb25NcyA/PyB0aGlzLkRFRkFVTFRfRFVSQVRJT05fTVM7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVxdWVzdFByaWNlID0gYXdhaXQgcHJpY2luZ0NsaWVudC5nZXRQcmljZSh7XG4gICAgICAgIHNlcnZpY2VDb2RlOiAnQVdTTGFtYmRhJyxcbiAgICAgICAgcmVnaW9uOiB0aGlzLm5vcm1hbGl6ZVJlZ2lvbihyZWdpb24pLFxuICAgICAgICBmaWx0ZXJzOiBbXG4gICAgICAgICAgeyBmaWVsZDogJ2dyb3VwJywgdmFsdWU6ICdBV1MtTGFtYmRhLVJlcXVlc3RzJyB9LFxuICAgICAgICBdLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IGNvbXB1dGVQcmljZSA9IGF3YWl0IHByaWNpbmdDbGllbnQuZ2V0UHJpY2Uoe1xuICAgICAgICBzZXJ2aWNlQ29kZTogJ0FXU0xhbWJkYScsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW1xuICAgICAgICAgIHsgZmllbGQ6ICdncm91cCcsIHZhbHVlOiAnQVdTLUxhbWJkYS1EdXJhdGlvbicgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBhc3N1bXB0aW9ucyA9IFtcbiAgICAgICAgYEFzc3VtZXMgJHtpbnZvY2F0aW9ucy50b0xvY2FsZVN0cmluZygpfSBpbnZvY2F0aW9ucyBwZXIgbW9udGhgLFxuICAgICAgICBgQXNzdW1lcyAke2R1cmF0aW9uTXN9bXMgYXZlcmFnZSBleGVjdXRpb24gdGltZWAsXG4gICAgICAgIGBBc3N1bWVzICR7bWVtb3J5U2l6ZX1NQiBtZW1vcnkgYWxsb2NhdGlvbmAsXG4gICAgICBdO1xuXG4gICAgICBpZiAodGhpcy5jdXN0b21JbnZvY2F0aW9uc1Blck1vbnRoICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgYXNzdW1wdGlvbnMucHVzaCgnVXNpbmcgY3VzdG9tIGludm9jYXRpb24gY291bnQgYXNzdW1wdGlvbiBmcm9tIGNvbmZpZ3VyYXRpb24nKTtcbiAgICAgIH1cbiAgICAgIGlmICh0aGlzLmN1c3RvbUF2ZXJhZ2VEdXJhdGlvbk1zICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgYXNzdW1wdGlvbnMucHVzaCgnVXNpbmcgY3VzdG9tIGR1cmF0aW9uIGFzc3VtcHRpb24gZnJvbSBjb25maWd1cmF0aW9uJyk7XG4gICAgICB9XG5cbiAgICAgIGlmIChyZXF1ZXN0UHJpY2UgPT09IG51bGwgfHwgY29tcHV0ZVByaWNlID09PSBudWxsKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgICAgICBjb25maWRlbmNlOiAndW5rbm93bicsXG4gICAgICAgICAgYXNzdW1wdGlvbnM6IFtcbiAgICAgICAgICAgIGBQcmljaW5nIGRhdGEgbm90IGF2YWlsYWJsZSBmb3IgTGFtYmRhIGluIHJlZ2lvbiAke3JlZ2lvbn1gLFxuICAgICAgICAgICAgLi4uYXNzdW1wdGlvbnMsXG4gICAgICAgICAgXSxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVxdWVzdENvc3QgPSAoaW52b2NhdGlvbnMgLyAxMDAwMDAwKSAqIHJlcXVlc3RQcmljZTtcblxuICAgICAgY29uc3QgZ2JTZWNvbmRzID0gKG1lbW9yeVNpemUgLyAxMDI0KSAqIChkdXJhdGlvbk1zIC8gMTAwMCkgKiBpbnZvY2F0aW9ucztcbiAgICAgIGNvbnN0IGNvbXB1dGVDb3N0ID0gZ2JTZWNvbmRzICogY29tcHV0ZVByaWNlO1xuXG4gICAgICBjb25zdCB0b3RhbENvc3QgPSByZXF1ZXN0Q29zdCArIGNvbXB1dGVDb3N0O1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IHRvdGFsQ29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnbWVkaXVtJyxcbiAgICAgICAgYXNzdW1wdGlvbnMsXG4gICAgICB9O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zdCBhc3N1bXB0aW9ucyA9IFtcbiAgICAgICAgYEZhaWxlZCB0byBmZXRjaCBwcmljaW5nOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gLFxuICAgICAgICBgV291bGQgYXNzdW1lICR7aW52b2NhdGlvbnMudG9Mb2NhbGVTdHJpbmcoKX0gaW52b2NhdGlvbnMgcGVyIG1vbnRoYCxcbiAgICAgICAgYFdvdWxkIGFzc3VtZSAke2R1cmF0aW9uTXN9bXMgYXZlcmFnZSBleGVjdXRpb24gdGltZWAsXG4gICAgICAgIGBXb3VsZCBhc3N1bWUgJHttZW1vcnlTaXplfU1CIG1lbW9yeSBhbGxvY2F0aW9uYCxcbiAgICAgIF07XG5cbiAgICAgIGlmICh0aGlzLmN1c3RvbUludm9jYXRpb25zUGVyTW9udGggIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBhc3N1bXB0aW9ucy5wdXNoKCdVc2luZyBjdXN0b20gaW52b2NhdGlvbiBjb3VudCBhc3N1bXB0aW9uIGZyb20gY29uZmlndXJhdGlvbicpO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMuY3VzdG9tQXZlcmFnZUR1cmF0aW9uTXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBhc3N1bXB0aW9ucy5wdXNoKCdVc2luZyBjdXN0b20gZHVyYXRpb24gYXNzdW1wdGlvbiBmcm9tIGNvbmZpZ3VyYXRpb24nKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnMsXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgbm9ybWFsaXplUmVnaW9uKHJlZ2lvbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCByZWdpb25NYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICAndXMtZWFzdC0xJzogJ1VTIEVhc3QgKE4uIFZpcmdpbmlhKScsXG4gICAgICAndXMtZWFzdC0yJzogJ1VTIEVhc3QgKE9oaW8pJyxcbiAgICAgICd1cy13ZXN0LTEnOiAnVVMgV2VzdCAoTi4gQ2FsaWZvcm5pYSknLFxuICAgICAgJ3VzLXdlc3QtMic6ICdVUyBXZXN0IChPcmVnb24pJyxcbiAgICAgICdldS13ZXN0LTEnOiAnRVUgKElyZWxhbmQpJyxcbiAgICAgICdldS13ZXN0LTInOiAnRVUgKExvbmRvbiknLFxuICAgICAgJ2V1LXdlc3QtMyc6ICdFVSAoUGFyaXMpJyxcbiAgICAgICdldS1jZW50cmFsLTEnOiAnRVUgKEZyYW5rZnVydCknLFxuICAgICAgJ2V1LW5vcnRoLTEnOiAnRVUgKFN0b2NraG9sbSknLFxuICAgICAgJ2FwLXNvdXRoLTEnOiAnQXNpYSBQYWNpZmljIChNdW1iYWkpJyxcbiAgICAgICdhcC1zb3V0aGVhc3QtMSc6ICdBc2lhIFBhY2lmaWMgKFNpbmdhcG9yZSknLFxuICAgICAgJ2FwLXNvdXRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU3lkbmV5KScsXG4gICAgICAnYXAtbm9ydGhlYXN0LTEnOiAnQXNpYSBQYWNpZmljIChUb2t5byknLFxuICAgICAgJ2FwLW5vcnRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU2VvdWwpJyxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHJlZ2lvbk1hcFtyZWdpb25dIHx8IHJlZ2lvbjtcbiAgfVxufVxuIl19
@@ -0,0 +1,16 @@
1
+ import { ResourceWithId } from '../../diff/types';
2
+ import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
3
+ export declare class NLBCalculator implements ResourceCostCalculator {
4
+ private customNewConnectionsPerSecond?;
5
+ private customActiveConnectionsPerMinute?;
6
+ private customProcessedBytesGB?;
7
+ private readonly DEFAULT_NEW_CONNECTIONS_PER_SECOND;
8
+ private readonly DEFAULT_ACTIVE_CONNECTIONS_PER_MINUTE;
9
+ private readonly DEFAULT_PROCESSED_BYTES_GB;
10
+ private readonly HOURS_PER_MONTH;
11
+ constructor(customNewConnectionsPerSecond?: number | undefined, customActiveConnectionsPerMinute?: number | undefined, customProcessedBytesGB?: number | undefined);
12
+ supports(resourceType: string): boolean;
13
+ calculateCost(resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
14
+ private normalizeRegion;
15
+ private getRegionPrefix;
16
+ }