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.
- package/.cdk-cost-analyzer-cache/metadata.json +12 -0
- package/.gitlab-ci.yml +214 -0
- package/.husky/pre-commit +12 -0
- package/.kiro/hooks/accessibility-audit.kiro.hook +18 -0
- package/.kiro/hooks/api-schema-validation.kiro.hook +21 -0
- package/.kiro/hooks/auto-test-on-save.kiro.hook +19 -0
- package/.kiro/hooks/cdk-synth-on-change.kiro.hook +20 -0
- package/.kiro/hooks/code-coverage-check.kiro.hook +14 -0
- package/.kiro/hooks/commit-message-helper.kiro.hook +14 -0
- package/.kiro/hooks/dependency-update-check.kiro.hook +14 -0
- package/.kiro/hooks/env-file-validation.kiro.hook +18 -0
- package/.kiro/hooks/lint-and-format-on-save.kiro.hook +21 -0
- package/.kiro/hooks/mcp-config-validation.kiro.hook +17 -0
- package/.kiro/hooks/mcp-server-test.kiro.hook +14 -0
- package/.kiro/hooks/performance-analysis.kiro.hook +14 -0
- package/.kiro/hooks/readme-spell-check.kiro.hook +14 -0
- package/.kiro/hooks/security-scan-on-dependency-change.kiro.hook +21 -0
- package/.kiro/hooks/translation-update.kiro.hook +18 -0
- package/.kiro/hooks/update-documentation.kiro.hook +18 -0
- package/.kiro/settings/mcp.json +20 -0
- package/.kiro/specs/cdk-cost-analyzer/design.md +620 -0
- package/.kiro/specs/cdk-cost-analyzer/requirements.md +183 -0
- package/.kiro/specs/cdk-cost-analyzer/tasks.md +357 -0
- package/.kiro/specs/github-actions-ci/design.md +281 -0
- package/.kiro/specs/github-actions-ci/requirements.md +86 -0
- package/.kiro/specs/github-actions-ci/tasks.md +115 -0
- package/.kiro/specs/nlb-calculator-test-coverage/design.md +190 -0
- package/.kiro/specs/nlb-calculator-test-coverage/requirements.md +84 -0
- package/.kiro/specs/nlb-calculator-test-coverage/tasks.md +150 -0
- package/.kiro/specs/production-readiness/design.md +1213 -0
- package/.kiro/specs/production-readiness/requirements.md +312 -0
- package/.kiro/specs/production-readiness/tasks.md +269 -0
- package/.kiro/specs/repository-cleanup/design.md +283 -0
- package/.kiro/specs/repository-cleanup/requirements.md +74 -0
- package/.kiro/specs/repository-cleanup/tasks.md +64 -0
- package/.kiro/steering/aws-cli-best-practices.md +41 -0
- package/.kiro/steering/cdk-best-practices.md +49 -0
- package/.kiro/steering/development-standards.md +54 -0
- package/.kiro/steering/docker-best-practices.md +34 -0
- package/.kiro/steering/documentation-style.md +151 -0
- package/.kiro/steering/git-best-practices.md +37 -0
- package/.kiro/steering/mcp-best-practices.md +95 -0
- package/.kiro/steering/python-best-practices.md +48 -0
- package/.kiro/steering/react-best-practices.md +44 -0
- package/.kiro/steering/security-best-practices.md +41 -0
- package/.kiro/steering/testing-best-practices.md +59 -0
- package/.kiro/steering/typescript-best-practices.md +40 -0
- package/CHANGELOG.md +49 -0
- package/CONTRIBUTING.md +258 -0
- package/LICENSE +19 -0
- package/README.md +480 -0
- package/SECURITY.md +117 -0
- package/dist/api/index.d.ts +11 -0
- package/dist/api/index.js +65 -0
- package/dist/api/types.d.ts +15 -0
- package/dist/api/types.js +3 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +262 -0
- package/dist/config/ConfigManager.d.ts +40 -0
- package/dist/config/ConfigManager.js +238 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +19 -0
- package/dist/config/types.d.ts +72 -0
- package/dist/config/types.js +15 -0
- package/dist/diff/DiffEngine.d.ts +7 -0
- package/dist/diff/DiffEngine.js +73 -0
- package/dist/diff/index.d.ts +2 -0
- package/dist/diff/index.js +21 -0
- package/dist/diff/types.d.ts +20 -0
- package/dist/diff/types.js +3 -0
- package/dist/integrations/GitLabIntegration.d.ts +7 -0
- package/dist/integrations/GitLabIntegration.js +45 -0
- package/dist/integrations/index.d.ts +2 -0
- package/dist/integrations/index.js +21 -0
- package/dist/integrations/types.d.ts +11 -0
- package/dist/integrations/types.js +13 -0
- package/dist/parser/TemplateParser.d.ts +8 -0
- package/dist/parser/TemplateParser.js +75 -0
- package/dist/parser/index.d.ts +2 -0
- package/dist/parser/index.js +22 -0
- package/dist/parser/types.d.ts +30 -0
- package/dist/parser/types.js +3 -0
- package/dist/pipeline/PipelineOrchestrator.d.ts +23 -0
- package/dist/pipeline/PipelineOrchestrator.js +191 -0
- package/dist/pipeline/index.d.ts +2 -0
- package/dist/pipeline/index.js +19 -0
- package/dist/pipeline/types.d.ts +41 -0
- package/dist/pipeline/types.js +13 -0
- package/dist/pricing/CacheManager.d.ts +75 -0
- package/dist/pricing/CacheManager.js +195 -0
- package/dist/pricing/PricingClient.d.ts +17 -0
- package/dist/pricing/PricingClient.js +122 -0
- package/dist/pricing/PricingService.d.ts +16 -0
- package/dist/pricing/PricingService.js +149 -0
- package/dist/pricing/calculators/ALBCalculator.d.ts +16 -0
- package/dist/pricing/calculators/ALBCalculator.js +163 -0
- package/dist/pricing/calculators/APIGatewayCalculator.d.ts +10 -0
- package/dist/pricing/calculators/APIGatewayCalculator.js +177 -0
- package/dist/pricing/calculators/CloudFrontCalculator.d.ts +59 -0
- package/dist/pricing/calculators/CloudFrontCalculator.js +151 -0
- package/dist/pricing/calculators/DynamoDBCalculator.d.ts +9 -0
- package/dist/pricing/calculators/DynamoDBCalculator.js +146 -0
- package/dist/pricing/calculators/EC2Calculator.d.ts +7 -0
- package/dist/pricing/calculators/EC2Calculator.js +80 -0
- package/dist/pricing/calculators/ECSCalculator.d.ts +9 -0
- package/dist/pricing/calculators/ECSCalculator.js +116 -0
- package/dist/pricing/calculators/ElastiCacheCalculator.d.ts +8 -0
- package/dist/pricing/calculators/ElastiCacheCalculator.js +106 -0
- package/dist/pricing/calculators/LambdaCalculator.d.ts +13 -0
- package/dist/pricing/calculators/LambdaCalculator.js +111 -0
- package/dist/pricing/calculators/NLBCalculator.d.ts +16 -0
- package/dist/pricing/calculators/NLBCalculator.js +138 -0
- package/dist/pricing/calculators/NatGatewayCalculator.d.ts +12 -0
- package/dist/pricing/calculators/NatGatewayCalculator.js +116 -0
- package/dist/pricing/calculators/RDSCalculator.d.ts +9 -0
- package/dist/pricing/calculators/RDSCalculator.js +103 -0
- package/dist/pricing/calculators/S3Calculator.d.ts +8 -0
- package/dist/pricing/calculators/S3Calculator.js +68 -0
- package/dist/pricing/calculators/VPCEndpointCalculator.d.ts +12 -0
- package/dist/pricing/calculators/VPCEndpointCalculator.js +129 -0
- package/dist/pricing/index.d.ts +10 -0
- package/dist/pricing/index.js +37 -0
- package/dist/pricing/types.d.ts +53 -0
- package/dist/pricing/types.js +22 -0
- package/dist/releasetag.txt +1 -0
- package/dist/reporter/Reporter.d.ts +18 -0
- package/dist/reporter/Reporter.js +412 -0
- package/dist/reporter/index.d.ts +2 -0
- package/dist/reporter/index.js +21 -0
- package/dist/reporter/types.d.ts +72 -0
- package/dist/reporter/types.js +3 -0
- package/dist/synthesis/SynthesisOrchestrator.d.ts +26 -0
- package/dist/synthesis/SynthesisOrchestrator.js +243 -0
- package/dist/synthesis/index.d.ts +2 -0
- package/dist/synthesis/index.js +19 -0
- package/dist/synthesis/types.d.ts +17 -0
- package/dist/synthesis/types.js +13 -0
- package/dist/threshold/ThresholdEnforcer.d.ts +29 -0
- package/dist/threshold/ThresholdEnforcer.js +143 -0
- package/dist/threshold/index.d.ts +2 -0
- package/dist/threshold/index.js +19 -0
- package/dist/threshold/types.d.ts +15 -0
- package/dist/threshold/types.js +17 -0
- package/docs/CALCULATORS.md +820 -0
- package/docs/CI_CD.md +608 -0
- package/docs/CONFIGURATION.md +407 -0
- package/docs/DEVELOPMENT.md +387 -0
- package/docs/RELEASE.md +223 -0
- package/docs/TROUBLESHOOTING.md +847 -0
- package/examples/.cdk-cost-analyzer.yml +85 -0
- package/examples/.gitlab-ci.yml +125 -0
- package/examples/api-usage.js +26 -0
- package/examples/complex/base.json +16 -0
- package/examples/complex/target.json +29 -0
- package/examples/monorepo/.gitlab-ci.yml +251 -0
- package/examples/monorepo/README.md +341 -0
- package/examples/monorepo/package.json +27 -0
- package/examples/monorepo/packages/backend-infra/.cdk-cost-analyzer.yml +34 -0
- package/examples/monorepo/packages/backend-infra/bin/app.ts +16 -0
- package/examples/monorepo/packages/backend-infra/cdk.json +7 -0
- package/examples/monorepo/packages/backend-infra/lib/backend-stack.ts +128 -0
- package/examples/monorepo/packages/backend-infra/package.json +30 -0
- package/examples/monorepo/packages/backend-infra/tsconfig.json +11 -0
- package/examples/monorepo/packages/data-infra/.cdk-cost-analyzer.yml +38 -0
- package/examples/monorepo/packages/data-infra/bin/app.ts +16 -0
- package/examples/monorepo/packages/data-infra/cdk.json +7 -0
- package/examples/monorepo/packages/data-infra/lib/data-stack.ts +121 -0
- package/examples/monorepo/packages/data-infra/package.json +30 -0
- package/examples/monorepo/packages/data-infra/tsconfig.json +11 -0
- package/examples/monorepo/packages/frontend-infra/.cdk-cost-analyzer.yml +31 -0
- package/examples/monorepo/packages/frontend-infra/bin/app.ts +16 -0
- package/examples/monorepo/packages/frontend-infra/cdk.json +7 -0
- package/examples/monorepo/packages/frontend-infra/lib/frontend-stack.ts +60 -0
- package/examples/monorepo/packages/frontend-infra/package.json +30 -0
- package/examples/monorepo/packages/frontend-infra/tsconfig.json +11 -0
- package/examples/monorepo/tsconfig.json +35 -0
- package/examples/multi-stack/.cdk-cost-analyzer.yml +72 -0
- package/examples/multi-stack/.gitlab-ci.yml +184 -0
- package/examples/multi-stack/README.md +279 -0
- package/examples/multi-stack/bin/app.ts +36 -0
- package/examples/multi-stack/cdk.json +72 -0
- package/examples/multi-stack/lib/compute-stack.ts +128 -0
- package/examples/multi-stack/lib/networking-stack.ts +69 -0
- package/examples/multi-stack/lib/storage-stack.ts +141 -0
- package/examples/multi-stack/package-lock.json +4437 -0
- package/examples/multi-stack/package.json +42 -0
- package/examples/multi-stack/tsconfig.json +34 -0
- package/examples/simple/base.json +8 -0
- package/examples/simple/target.json +14 -0
- package/examples/single-stack/.NVP +0 -0
- package/examples/single-stack/.cdk-cost-analyzer.yml +52 -0
- package/examples/single-stack/.gitlab-ci.yml +126 -0
- package/examples/single-stack/README.md +184 -0
- package/examples/single-stack/UeK +0 -0
- package/examples/single-stack/bin/app.ts +16 -0
- package/examples/single-stack/cdk.json +72 -0
- package/examples/single-stack/lib/infrastructure-stack.ts +119 -0
- package/examples/single-stack/package-lock.json +4443 -0
- package/examples/single-stack/package.json +38 -0
- package/examples/single-stack/tsconfig.json +34 -0
- package/package.json +139 -0
- package/test-cdk-project/README-COMPUTE.md +141 -0
- package/test-cdk-project/README.md +95 -0
- package/test-cdk-project/app-with-compute.js +102 -0
- package/test-cdk-project/app.js +81 -0
- package/test-cdk-project/cdk-compute.json +3 -0
- package/test-cdk-project/cdk.context.json +7 -0
- package/test-cdk-project/cdk.json +3 -0
- package/test-cdk-project/cdk.out/TestStack.assets.json +21 -0
- package/test-cdk-project/cdk.out/TestStack.template.json +115 -0
- package/test-cdk-project/cdk.out/cdk.out +1 -0
- package/test-cdk-project/cdk.out/manifest.json +503 -0
- package/test-cdk-project/cdk.out/tree.json +1 -0
- package/test-cdk-project/cdk.out.base/TestStack.assets.json +21 -0
- package/test-cdk-project/cdk.out.base/TestStack.template.json +115 -0
- package/test-cdk-project/cdk.out.base/cdk.out +1 -0
- package/test-cdk-project/cdk.out.base/manifest.json +503 -0
- package/test-cdk-project/cdk.out.base/tree.json +1 -0
- package/test-cdk-project/cdk.out.target/TestStack.assets.json +21 -0
- package/test-cdk-project/cdk.out.target/TestStack.template.json +183 -0
- package/test-cdk-project/cdk.out.target/cdk.out +1 -0
- package/test-cdk-project/cdk.out.target/manifest.json +521 -0
- package/test-cdk-project/cdk.out.target/tree.json +1 -0
- package/test-cdk-project/package-lock.json +422 -0
- package/test-cdk-project/package.json +17 -0
- package/tools/workflows/README.md +102 -0
- package/tools/workflows/validate-workflows.js +109 -0
- package/tools/workflows/workflow-utils.ts +181 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.APIGatewayCalculator = void 0;
|
|
4
|
+
class APIGatewayCalculator {
|
|
5
|
+
supports(resourceType) {
|
|
6
|
+
return resourceType === 'AWS::ApiGateway::RestApi' ||
|
|
7
|
+
resourceType === 'AWS::ApiGatewayV2::Api';
|
|
8
|
+
}
|
|
9
|
+
async calculateCost(resource, region, pricingClient) {
|
|
10
|
+
const isV2 = resource.type === 'AWS::ApiGatewayV2::Api';
|
|
11
|
+
const protocolType = isV2 ? resource.properties.ProtocolType : 'REST';
|
|
12
|
+
if (protocolType === 'WEBSOCKET') {
|
|
13
|
+
return this.calculateWebSocketCost(region, pricingClient);
|
|
14
|
+
}
|
|
15
|
+
else if (protocolType === 'HTTP') {
|
|
16
|
+
return this.calculateHttpApiCost(region, pricingClient);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
return this.calculateRestApiCost(region, pricingClient);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async calculateRestApiCost(region, pricingClient) {
|
|
23
|
+
try {
|
|
24
|
+
const assumedRequests = 1_000_000; // 1M requests per month
|
|
25
|
+
const costPerMillion = await pricingClient.getPrice({
|
|
26
|
+
serviceCode: 'AmazonApiGateway',
|
|
27
|
+
region: this.normalizeRegion(region),
|
|
28
|
+
filters: [
|
|
29
|
+
{ field: 'productFamily', value: 'API Calls' },
|
|
30
|
+
{ field: 'groupDescription', value: 'ApiGatewayRequest' },
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
if (costPerMillion === null) {
|
|
34
|
+
return {
|
|
35
|
+
amount: 0,
|
|
36
|
+
currency: 'USD',
|
|
37
|
+
confidence: 'unknown',
|
|
38
|
+
assumptions: ['Pricing data not available for API Gateway REST API'],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const monthlyCost = (assumedRequests / 1_000_000) * costPerMillion;
|
|
42
|
+
return {
|
|
43
|
+
amount: monthlyCost,
|
|
44
|
+
currency: 'USD',
|
|
45
|
+
confidence: 'medium',
|
|
46
|
+
assumptions: [
|
|
47
|
+
`Assumes ${assumedRequests.toLocaleString()} REST API requests per month`,
|
|
48
|
+
'REST API type',
|
|
49
|
+
'Does not include data transfer, caching, or other features',
|
|
50
|
+
'First 333M requests may have tiered pricing (not calculated)',
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
return {
|
|
56
|
+
amount: 0,
|
|
57
|
+
currency: 'USD',
|
|
58
|
+
confidence: 'unknown',
|
|
59
|
+
assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async calculateHttpApiCost(region, pricingClient) {
|
|
64
|
+
try {
|
|
65
|
+
const assumedRequests = 1_000_000; // 1M requests per month
|
|
66
|
+
const costPerMillion = await pricingClient.getPrice({
|
|
67
|
+
serviceCode: 'AmazonApiGateway',
|
|
68
|
+
region: this.normalizeRegion(region),
|
|
69
|
+
filters: [
|
|
70
|
+
{ field: 'productFamily', value: 'API Calls' },
|
|
71
|
+
{ field: 'groupDescription', value: 'ApiGatewayHttpRequest' },
|
|
72
|
+
],
|
|
73
|
+
});
|
|
74
|
+
if (costPerMillion === null) {
|
|
75
|
+
return {
|
|
76
|
+
amount: 0,
|
|
77
|
+
currency: 'USD',
|
|
78
|
+
confidence: 'unknown',
|
|
79
|
+
assumptions: ['Pricing data not available for API Gateway HTTP API'],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const monthlyCost = (assumedRequests / 1_000_000) * costPerMillion;
|
|
83
|
+
return {
|
|
84
|
+
amount: monthlyCost,
|
|
85
|
+
currency: 'USD',
|
|
86
|
+
confidence: 'medium',
|
|
87
|
+
assumptions: [
|
|
88
|
+
`Assumes ${assumedRequests.toLocaleString()} HTTP API requests per month`,
|
|
89
|
+
'HTTP API type',
|
|
90
|
+
'Does not include data transfer costs',
|
|
91
|
+
'First 300M requests may have tiered pricing (not calculated)',
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
return {
|
|
97
|
+
amount: 0,
|
|
98
|
+
currency: 'USD',
|
|
99
|
+
confidence: 'unknown',
|
|
100
|
+
assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async calculateWebSocketCost(region, pricingClient) {
|
|
105
|
+
try {
|
|
106
|
+
const assumedMessages = 1_000_000; // 1M messages per month
|
|
107
|
+
const assumedConnectionMinutes = 100_000; // 100K connection minutes
|
|
108
|
+
const messageCostPerMillion = await pricingClient.getPrice({
|
|
109
|
+
serviceCode: 'AmazonApiGateway',
|
|
110
|
+
region: this.normalizeRegion(region),
|
|
111
|
+
filters: [
|
|
112
|
+
{ field: 'productFamily', value: 'WebSocket' },
|
|
113
|
+
{ field: 'groupDescription', value: 'ApiGatewayMessage' },
|
|
114
|
+
],
|
|
115
|
+
});
|
|
116
|
+
const connectionCostPerMinute = await pricingClient.getPrice({
|
|
117
|
+
serviceCode: 'AmazonApiGateway',
|
|
118
|
+
region: this.normalizeRegion(region),
|
|
119
|
+
filters: [
|
|
120
|
+
{ field: 'productFamily', value: 'WebSocket' },
|
|
121
|
+
{ field: 'groupDescription', value: 'ApiGatewayConnectionMinute' },
|
|
122
|
+
],
|
|
123
|
+
});
|
|
124
|
+
if (messageCostPerMillion === null || connectionCostPerMinute === null) {
|
|
125
|
+
return {
|
|
126
|
+
amount: 0,
|
|
127
|
+
currency: 'USD',
|
|
128
|
+
confidence: 'unknown',
|
|
129
|
+
assumptions: ['Pricing data not available for API Gateway WebSocket API'],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const messageCost = (assumedMessages / 1_000_000) * messageCostPerMillion;
|
|
133
|
+
const connectionCost = assumedConnectionMinutes * connectionCostPerMinute;
|
|
134
|
+
const monthlyCost = messageCost + connectionCost;
|
|
135
|
+
return {
|
|
136
|
+
amount: monthlyCost,
|
|
137
|
+
currency: 'USD',
|
|
138
|
+
confidence: 'medium',
|
|
139
|
+
assumptions: [
|
|
140
|
+
`Assumes ${assumedMessages.toLocaleString()} WebSocket messages per month`,
|
|
141
|
+
`Assumes ${assumedConnectionMinutes.toLocaleString()} connection minutes per month`,
|
|
142
|
+
'WebSocket API type',
|
|
143
|
+
'Does not include data transfer costs',
|
|
144
|
+
],
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
return {
|
|
149
|
+
amount: 0,
|
|
150
|
+
currency: 'USD',
|
|
151
|
+
confidence: 'unknown',
|
|
152
|
+
assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
normalizeRegion(region) {
|
|
157
|
+
const regionMap = {
|
|
158
|
+
'us-east-1': 'US East (N. Virginia)',
|
|
159
|
+
'us-east-2': 'US East (Ohio)',
|
|
160
|
+
'us-west-1': 'US West (N. California)',
|
|
161
|
+
'us-west-2': 'US West (Oregon)',
|
|
162
|
+
'eu-west-1': 'EU (Ireland)',
|
|
163
|
+
'eu-west-2': 'EU (London)',
|
|
164
|
+
'eu-west-3': 'EU (Paris)',
|
|
165
|
+
'eu-central-1': 'EU (Frankfurt)',
|
|
166
|
+
'eu-north-1': 'EU (Stockholm)',
|
|
167
|
+
'ap-south-1': 'Asia Pacific (Mumbai)',
|
|
168
|
+
'ap-southeast-1': 'Asia Pacific (Singapore)',
|
|
169
|
+
'ap-southeast-2': 'Asia Pacific (Sydney)',
|
|
170
|
+
'ap-northeast-1': 'Asia Pacific (Tokyo)',
|
|
171
|
+
'ap-northeast-2': 'Asia Pacific (Seoul)',
|
|
172
|
+
};
|
|
173
|
+
return regionMap[region] || region;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
exports.APIGatewayCalculator = APIGatewayCalculator;
|
|
177
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQVBJR2F0ZXdheUNhbGN1bGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcHJpY2luZy9jYWxjdWxhdG9ycy9BUElHYXRld2F5Q2FsY3VsYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFHQSxNQUFhLG9CQUFvQjtJQUMvQixRQUFRLENBQUMsWUFBb0I7UUFDM0IsT0FBTyxZQUFZLEtBQUssMEJBQTBCO1lBQzNDLFlBQVksS0FBSyx3QkFBd0IsQ0FBQztJQUNuRCxDQUFDO0lBRUQsS0FBSyxDQUFDLGFBQWEsQ0FDakIsUUFBd0IsRUFDeEIsTUFBYyxFQUNkLGFBQTRCO1FBRTVCLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxJQUFJLEtBQUssd0JBQXdCLENBQUM7UUFDeEQsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBRSxRQUFRLENBQUMsVUFBVSxDQUFDLFlBQXVCLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztRQUVsRixJQUFJLFlBQVksS0FBSyxXQUFXLEVBQUUsQ0FBQztZQUNqQyxPQUFPLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxNQUFNLEVBQUUsYUFBYSxDQUFDLENBQUM7UUFDNUQsQ0FBQzthQUFNLElBQUksWUFBWSxLQUFLLE1BQU0sRUFBRSxDQUFDO1lBQ25DLE9BQU8sSUFBSSxDQUFDLG9CQUFvQixDQUFDLE1BQU0sRUFBRSxhQUFhLENBQUMsQ0FBQztRQUMxRCxDQUFDO2FBQU0sQ0FBQztZQUNOLE9BQU8sSUFBSSxDQUFDLG9CQUFvQixDQUFDLE1BQU0sRUFBRSxhQUFhLENBQUMsQ0FBQztRQUMxRCxDQUFDO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxvQkFBb0IsQ0FDaEMsTUFBYyxFQUNkLGFBQTRCO1FBRTVCLElBQUksQ0FBQztZQUNILE1BQU0sZUFBZSxHQUFHLFNBQVMsQ0FBQyxDQUFDLHdCQUF3QjtZQUUzRCxNQUFNLGNBQWMsR0FBRyxNQUFNLGFBQWEsQ0FBQyxR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LFdBQVcsRUFBRSxZQUFZO1lBQ3pCLGNBQWMsRUFBRSxnQkFBZ0I7WUFDaEMsWUFBWSxFQUFFLGdCQUFnQjtZQUM5QixZQUFZLEVBQUUsdUJBQXVCO1lBQ3JDLGdCQUFnQixFQUFFLDBCQUEwQjtZQUM1QyxnQkFBZ0IsRUFBRSx1QkFBdUI7WUFDekMsZ0JBQWdCLEVBQUUsc0JBQXNCO1lBQ3hDLGdCQUFnQixFQUFFLHNCQUFzQjtTQUN6QyxDQUFDO1FBRUYsT0FBTyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksTUFBTSxDQUFDO0lBQ3JDLENBQUM7Q0FDRjtBQXZNRCxvREF1TUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXNvdXJjZVdpdGhJZCB9IGZyb20gJy4uLy4uL2RpZmYvdHlwZXMnO1xuaW1wb3J0IHsgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciwgTW9udGhseUNvc3QsIFByaWNpbmdDbGllbnQgfSBmcm9tICcuLi90eXBlcyc7XG5cbmV4cG9ydCBjbGFzcyBBUElHYXRld2F5Q2FsY3VsYXRvciBpbXBsZW1lbnRzIFJlc291cmNlQ29zdENhbGN1bGF0b3Ige1xuICBzdXBwb3J0cyhyZXNvdXJjZVR5cGU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiByZXNvdXJjZVR5cGUgPT09ICdBV1M6OkFwaUdhdGV3YXk6OlJlc3RBcGknIHx8XG4gICAgICAgICAgIHJlc291cmNlVHlwZSA9PT0gJ0FXUzo6QXBpR2F0ZXdheVYyOjpBcGknO1xuICB9XG5cbiAgYXN5bmMgY2FsY3VsYXRlQ29zdChcbiAgICByZXNvdXJjZTogUmVzb3VyY2VXaXRoSWQsXG4gICAgcmVnaW9uOiBzdHJpbmcsXG4gICAgcHJpY2luZ0NsaWVudDogUHJpY2luZ0NsaWVudCxcbiAgKTogUHJvbWlzZTxNb250aGx5Q29zdD4ge1xuICAgIGNvbnN0IGlzVjIgPSByZXNvdXJjZS50eXBlID09PSAnQVdTOjpBcGlHYXRld2F5VjI6OkFwaSc7XG4gICAgY29uc3QgcHJvdG9jb2xUeXBlID0gaXNWMiA/IChyZXNvdXJjZS5wcm9wZXJ0aWVzLlByb3RvY29sVHlwZSBhcyBzdHJpbmcpIDogJ1JFU1QnO1xuXG4gICAgaWYgKHByb3RvY29sVHlwZSA9PT0gJ1dFQlNPQ0tFVCcpIHtcbiAgICAgIHJldHVybiB0aGlzLmNhbGN1bGF0ZVdlYlNvY2tldENvc3QocmVnaW9uLCBwcmljaW5nQ2xpZW50KTtcbiAgICB9IGVsc2UgaWYgKHByb3RvY29sVHlwZSA9PT0gJ0hUVFAnKSB7XG4gICAgICByZXR1cm4gdGhpcy5jYWxjdWxhdGVIdHRwQXBpQ29zdChyZWdpb24sIHByaWNpbmdDbGllbnQpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gdGhpcy5jYWxjdWxhdGVSZXN0QXBpQ29zdChyZWdpb24sIHByaWNpbmdDbGllbnQpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgY2FsY3VsYXRlUmVzdEFwaUNvc3QoXG4gICAgcmVnaW9uOiBzdHJpbmcsXG4gICAgcHJpY2luZ0NsaWVudDogUHJpY2luZ0NsaWVudCxcbiAgKTogUHJvbWlzZTxNb250aGx5Q29zdD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBhc3N1bWVkUmVxdWVzdHMgPSAxXzAwMF8wMDA7IC8vIDFNIHJlcXVlc3RzIHBlciBtb250aFxuXG4gICAgICBjb25zdCBjb3N0UGVyTWlsbGlvbiA9IGF3YWl0IHByaWNpbmdDbGllbnQuZ2V0UHJpY2Uoe1xuICAgICAgICBzZXJ2aWNlQ29kZTogJ0FtYXpvbkFwaUdhdGV3YXknLFxuICAgICAgICByZWdpb246IHRoaXMubm9ybWFsaXplUmVnaW9uKHJlZ2lvbiksXG4gICAgICAgIGZpbHRlcnM6IFtcbiAgICAgICAgICB7IGZpZWxkOiAncHJvZHVjdEZhbWlseScsIHZhbHVlOiAnQVBJIENhbGxzJyB9LFxuICAgICAgICAgIHsgZmllbGQ6ICdncm91cERlc2NyaXB0aW9uJywgdmFsdWU6ICdBcGlHYXRld2F5UmVxdWVzdCcgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoY29zdFBlck1pbGxpb24gPT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgICBhc3N1bXB0aW9uczogWydQcmljaW5nIGRhdGEgbm90IGF2YWlsYWJsZSBmb3IgQVBJIEdhdGV3YXkgUkVTVCBBUEknXSxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbW9udGhseUNvc3QgPSAoYXNzdW1lZFJlcXVlc3RzIC8gMV8wMDBfMDAwKSAqIGNvc3RQZXJNaWxsaW9uO1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IG1vbnRobHlDb3N0LFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICdtZWRpdW0nLFxuICAgICAgICBhc3N1bXB0aW9uczogW1xuICAgICAgICAgIGBBc3N1bWVzICR7YXNzdW1lZFJlcXVlc3RzLnRvTG9jYWxlU3RyaW5nKCl9IFJFU1QgQVBJIHJlcXVlc3RzIHBlciBtb250aGAsXG4gICAgICAgICAgJ1JFU1QgQVBJIHR5cGUnLFxuICAgICAgICAgICdEb2VzIG5vdCBpbmNsdWRlIGRhdGEgdHJhbnNmZXIsIGNhY2hpbmcsIG9yIG90aGVyIGZlYXR1cmVzJyxcbiAgICAgICAgICAnRmlyc3QgMzMzTSByZXF1ZXN0cyBtYXkgaGF2ZSB0aWVyZWQgcHJpY2luZyAobm90IGNhbGN1bGF0ZWQpJyxcbiAgICAgICAgXSxcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAndW5rbm93bicsXG4gICAgICAgIGFzc3VtcHRpb25zOiBbYEZhaWxlZCB0byBmZXRjaCBwcmljaW5nOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gXSxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjYWxjdWxhdGVIdHRwQXBpQ29zdChcbiAgICByZWdpb246IHN0cmluZyxcbiAgICBwcmljaW5nQ2xpZW50OiBQcmljaW5nQ2xpZW50LFxuICApOiBQcm9taXNlPE1vbnRobHlDb3N0PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGFzc3VtZWRSZXF1ZXN0cyA9IDFfMDAwXzAwMDsgLy8gMU0gcmVxdWVzdHMgcGVyIG1vbnRoXG5cbiAgICAgIGNvbnN0IGNvc3RQZXJNaWxsaW9uID0gYXdhaXQgcHJpY2luZ0NsaWVudC5nZXRQcmljZSh7XG4gICAgICAgIHNlcnZpY2VDb2RlOiAnQW1hem9uQXBpR2F0ZXdheScsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW1xuICAgICAgICAgIHsgZmllbGQ6ICdwcm9kdWN0RmFtaWx5JywgdmFsdWU6ICdBUEkgQ2FsbHMnIH0sXG4gICAgICAgICAgeyBmaWVsZDogJ2dyb3VwRGVzY3JpcHRpb24nLCB2YWx1ZTogJ0FwaUdhdGV3YXlIdHRwUmVxdWVzdCcgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoY29zdFBlck1pbGxpb24gPT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgICBhc3N1bXB0aW9uczogWydQcmljaW5nIGRhdGEgbm90IGF2YWlsYWJsZSBmb3IgQVBJIEdhdGV3YXkgSFRUUCBBUEknXSxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbW9udGhseUNvc3QgPSAoYXNzdW1lZFJlcXVlc3RzIC8gMV8wMDBfMDAwKSAqIGNvc3RQZXJNaWxsaW9uO1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IG1vbnRobHlDb3N0LFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICdtZWRpdW0nLFxuICAgICAgICBhc3N1bXB0aW9uczogW1xuICAgICAgICAgIGBBc3N1bWVzICR7YXNzdW1lZFJlcXVlc3RzLnRvTG9jYWxlU3RyaW5nKCl9IEhUVFAgQVBJIHJlcXVlc3RzIHBlciBtb250aGAsXG4gICAgICAgICAgJ0hUVFAgQVBJIHR5cGUnLFxuICAgICAgICAgICdEb2VzIG5vdCBpbmNsdWRlIGRhdGEgdHJhbnNmZXIgY29zdHMnLFxuICAgICAgICAgICdGaXJzdCAzMDBNIHJlcXVlc3RzIG1heSBoYXZlIHRpZXJlZCBwcmljaW5nIChub3QgY2FsY3VsYXRlZCknLFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtgRmFpbGVkIHRvIGZldGNoIHByaWNpbmc6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWBdLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGNhbGN1bGF0ZVdlYlNvY2tldENvc3QoXG4gICAgcmVnaW9uOiBzdHJpbmcsXG4gICAgcHJpY2luZ0NsaWVudDogUHJpY2luZ0NsaWVudCxcbiAgKTogUHJvbWlzZTxNb250aGx5Q29zdD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBhc3N1bWVkTWVzc2FnZXMgPSAxXzAwMF8wMDA7IC8vIDFNIG1lc3NhZ2VzIHBlciBtb250aFxuICAgICAgY29uc3QgYXNzdW1lZENvbm5lY3Rpb25NaW51dGVzID0gMTAwXzAwMDsgLy8gMTAwSyBjb25uZWN0aW9uIG1pbnV0ZXNcblxuICAgICAgY29uc3QgbWVzc2FnZUNvc3RQZXJNaWxsaW9uID0gYXdhaXQgcHJpY2luZ0NsaWVudC5nZXRQcmljZSh7XG4gICAgICAgIHNlcnZpY2VDb2RlOiAnQW1hem9uQXBpR2F0ZXdheScsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW1xuICAgICAgICAgIHsgZmllbGQ6ICdwcm9kdWN0RmFtaWx5JywgdmFsdWU6ICdXZWJTb2NrZXQnIH0sXG4gICAgICAgICAgeyBmaWVsZDogJ2dyb3VwRGVzY3JpcHRpb24nLCB2YWx1ZTogJ0FwaUdhdGV3YXlNZXNzYWdlJyB9LFxuICAgICAgICBdLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IGNvbm5lY3Rpb25Db3N0UGVyTWludXRlID0gYXdhaXQgcHJpY2luZ0NsaWVudC5nZXRQcmljZSh7XG4gICAgICAgIHNlcnZpY2VDb2RlOiAnQW1hem9uQXBpR2F0ZXdheScsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW1xuICAgICAgICAgIHsgZmllbGQ6ICdwcm9kdWN0RmFtaWx5JywgdmFsdWU6ICdXZWJTb2NrZXQnIH0sXG4gICAgICAgICAgeyBmaWVsZDogJ2dyb3VwRGVzY3JpcHRpb24nLCB2YWx1ZTogJ0FwaUdhdGV3YXlDb25uZWN0aW9uTWludXRlJyB9LFxuICAgICAgICBdLFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChtZXNzYWdlQ29zdFBlck1pbGxpb24gPT09IG51bGwgfHwgY29ubmVjdGlvbkNvc3RQZXJNaW51dGUgPT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgICBhc3N1bXB0aW9uczogWydQcmljaW5nIGRhdGEgbm90IGF2YWlsYWJsZSBmb3IgQVBJIEdhdGV3YXkgV2ViU29ja2V0IEFQSSddLFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBtZXNzYWdlQ29zdCA9IChhc3N1bWVkTWVzc2FnZXMgLyAxXzAwMF8wMDApICogbWVzc2FnZUNvc3RQZXJNaWxsaW9uO1xuICAgICAgY29uc3QgY29ubmVjdGlvbkNvc3QgPSBhc3N1bWVkQ29ubmVjdGlvbk1pbnV0ZXMgKiBjb25uZWN0aW9uQ29zdFBlck1pbnV0ZTtcbiAgICAgIGNvbnN0IG1vbnRobHlDb3N0ID0gbWVzc2FnZUNvc3QgKyBjb25uZWN0aW9uQ29zdDtcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiBtb250aGx5Q29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnbWVkaXVtJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtcbiAgICAgICAgICBgQXNzdW1lcyAke2Fzc3VtZWRNZXNzYWdlcy50b0xvY2FsZVN0cmluZygpfSBXZWJTb2NrZXQgbWVzc2FnZXMgcGVyIG1vbnRoYCxcbiAgICAgICAgICBgQXNzdW1lcyAke2Fzc3VtZWRDb25uZWN0aW9uTWludXRlcy50b0xvY2FsZVN0cmluZygpfSBjb25uZWN0aW9uIG1pbnV0ZXMgcGVyIG1vbnRoYCxcbiAgICAgICAgICAnV2ViU29ja2V0IEFQSSB0eXBlJyxcbiAgICAgICAgICAnRG9lcyBub3QgaW5jbHVkZSBkYXRhIHRyYW5zZmVyIGNvc3RzJyxcbiAgICAgICAgXSxcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAndW5rbm93bicsXG4gICAgICAgIGFzc3VtcHRpb25zOiBbYEZhaWxlZCB0byBmZXRjaCBwcmljaW5nOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gXSxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBub3JtYWxpemVSZWdpb24ocmVnaW9uOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHJlZ2lvbk1hcDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICAgICd1cy1lYXN0LTEnOiAnVVMgRWFzdCAoTi4gVmlyZ2luaWEpJyxcbiAgICAgICd1cy1lYXN0LTInOiAnVVMgRWFzdCAoT2hpbyknLFxuICAgICAgJ3VzLXdlc3QtMSc6ICdVUyBXZXN0IChOLiBDYWxpZm9ybmlhKScsXG4gICAgICAndXMtd2VzdC0yJzogJ1VTIFdlc3QgKE9yZWdvbiknLFxuICAgICAgJ2V1LXdlc3QtMSc6ICdFVSAoSXJlbGFuZCknLFxuICAgICAgJ2V1LXdlc3QtMic6ICdFVSAoTG9uZG9uKScsXG4gICAgICAnZXUtd2VzdC0zJzogJ0VVIChQYXJpcyknLFxuICAgICAgJ2V1LWNlbnRyYWwtMSc6ICdFVSAoRnJhbmtmdXJ0KScsXG4gICAgICAnZXUtbm9ydGgtMSc6ICdFVSAoU3RvY2tob2xtKScsXG4gICAgICAnYXAtc291dGgtMSc6ICdBc2lhIFBhY2lmaWMgKE11bWJhaSknLFxuICAgICAgJ2FwLXNvdXRoZWFzdC0xJzogJ0FzaWEgUGFjaWZpYyAoU2luZ2Fwb3JlKScsXG4gICAgICAnYXAtc291dGhlYXN0LTInOiAnQXNpYSBQYWNpZmljIChTeWRuZXkpJyxcbiAgICAgICdhcC1ub3J0aGVhc3QtMSc6ICdBc2lhIFBhY2lmaWMgKFRva3lvKScsXG4gICAgICAnYXAtbm9ydGhlYXN0LTInOiAnQXNpYSBQYWNpZmljIChTZW91bCknLFxuICAgIH07XG5cbiAgICByZXR1cm4gcmVnaW9uTWFwW3JlZ2lvbl0gfHwgcmVnaW9uO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ResourceWithId } from '../../diff/types';
|
|
2
|
+
import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Calculator for AWS CloudFront distribution costs.
|
|
5
|
+
*
|
|
6
|
+
* Estimates monthly costs based on data transfer and request volumes.
|
|
7
|
+
* CloudFront pricing includes:
|
|
8
|
+
* - Data transfer out to internet (per GB)
|
|
9
|
+
* - HTTP/HTTPS requests (per 10,000 requests)
|
|
10
|
+
*
|
|
11
|
+
* @see https://aws.amazon.com/cloudfront/pricing/
|
|
12
|
+
*/
|
|
13
|
+
export declare class CloudFrontCalculator implements ResourceCostCalculator {
|
|
14
|
+
private readonly dataTransferGB?;
|
|
15
|
+
private readonly requests?;
|
|
16
|
+
private readonly DEFAULT_DATA_TRANSFER_GB;
|
|
17
|
+
private readonly DEFAULT_REQUESTS;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a CloudFront cost calculator.
|
|
20
|
+
*
|
|
21
|
+
* @param dataTransferGB - Optional custom data transfer volume in GB per month
|
|
22
|
+
* @param requests - Optional custom request count per month
|
|
23
|
+
*/
|
|
24
|
+
constructor(dataTransferGB?: number | undefined, requests?: number | undefined);
|
|
25
|
+
/**
|
|
26
|
+
* Checks if this calculator supports the given resource type.
|
|
27
|
+
*
|
|
28
|
+
* @param resourceType - CloudFormation resource type
|
|
29
|
+
* @returns true if resource type is AWS::CloudFront::Distribution
|
|
30
|
+
*/
|
|
31
|
+
supports(resourceType: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Calculates monthly cost for a CloudFront distribution.
|
|
34
|
+
*
|
|
35
|
+
* Cost components:
|
|
36
|
+
* - Data transfer out to internet (based on volume in GB)
|
|
37
|
+
* - HTTP/HTTPS requests (per 10,000 requests)
|
|
38
|
+
*
|
|
39
|
+
* Default assumptions:
|
|
40
|
+
* - 100 GB data transfer per month
|
|
41
|
+
* - 1,000,000 requests per month
|
|
42
|
+
*
|
|
43
|
+
* @param _resource - CloudFormation resource (properties not used for CloudFront)
|
|
44
|
+
* @param region - AWS region for pricing (CloudFront is global but pricing varies by region)
|
|
45
|
+
* @param pricingClient - Client for querying AWS Pricing API
|
|
46
|
+
* @returns Monthly cost estimate with assumptions and confidence level
|
|
47
|
+
*/
|
|
48
|
+
calculateCost(_resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
|
|
49
|
+
/**
|
|
50
|
+
* Normalizes AWS region code to AWS Pricing API region name.
|
|
51
|
+
*
|
|
52
|
+
* CloudFront is a global service, but pricing varies by region and the
|
|
53
|
+
* AWS Pricing API requires region names in specific format.
|
|
54
|
+
*
|
|
55
|
+
* @param region - AWS region code (e.g., 'us-east-1')
|
|
56
|
+
* @returns AWS Pricing API region name (e.g., 'US East (N. Virginia)')
|
|
57
|
+
*/
|
|
58
|
+
private normalizeRegion;
|
|
59
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CloudFrontCalculator = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Calculator for AWS CloudFront distribution costs.
|
|
6
|
+
*
|
|
7
|
+
* Estimates monthly costs based on data transfer and request volumes.
|
|
8
|
+
* CloudFront pricing includes:
|
|
9
|
+
* - Data transfer out to internet (per GB)
|
|
10
|
+
* - HTTP/HTTPS requests (per 10,000 requests)
|
|
11
|
+
*
|
|
12
|
+
* @see https://aws.amazon.com/cloudfront/pricing/
|
|
13
|
+
*/
|
|
14
|
+
class CloudFrontCalculator {
|
|
15
|
+
dataTransferGB;
|
|
16
|
+
requests;
|
|
17
|
+
DEFAULT_DATA_TRANSFER_GB = 100;
|
|
18
|
+
DEFAULT_REQUESTS = 1000000;
|
|
19
|
+
/**
|
|
20
|
+
* Creates a CloudFront cost calculator.
|
|
21
|
+
*
|
|
22
|
+
* @param dataTransferGB - Optional custom data transfer volume in GB per month
|
|
23
|
+
* @param requests - Optional custom request count per month
|
|
24
|
+
*/
|
|
25
|
+
constructor(dataTransferGB, requests) {
|
|
26
|
+
this.dataTransferGB = dataTransferGB;
|
|
27
|
+
this.requests = requests;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Checks if this calculator supports the given resource type.
|
|
31
|
+
*
|
|
32
|
+
* @param resourceType - CloudFormation resource type
|
|
33
|
+
* @returns true if resource type is AWS::CloudFront::Distribution
|
|
34
|
+
*/
|
|
35
|
+
supports(resourceType) {
|
|
36
|
+
return resourceType === 'AWS::CloudFront::Distribution';
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Calculates monthly cost for a CloudFront distribution.
|
|
40
|
+
*
|
|
41
|
+
* Cost components:
|
|
42
|
+
* - Data transfer out to internet (based on volume in GB)
|
|
43
|
+
* - HTTP/HTTPS requests (per 10,000 requests)
|
|
44
|
+
*
|
|
45
|
+
* Default assumptions:
|
|
46
|
+
* - 100 GB data transfer per month
|
|
47
|
+
* - 1,000,000 requests per month
|
|
48
|
+
*
|
|
49
|
+
* @param _resource - CloudFormation resource (properties not used for CloudFront)
|
|
50
|
+
* @param region - AWS region for pricing (CloudFront is global but pricing varies by region)
|
|
51
|
+
* @param pricingClient - Client for querying AWS Pricing API
|
|
52
|
+
* @returns Monthly cost estimate with assumptions and confidence level
|
|
53
|
+
*/
|
|
54
|
+
async calculateCost(_resource, region, pricingClient) {
|
|
55
|
+
const dataTransfer = this.dataTransferGB ?? this.DEFAULT_DATA_TRANSFER_GB;
|
|
56
|
+
const requestCount = this.requests ?? this.DEFAULT_REQUESTS;
|
|
57
|
+
try {
|
|
58
|
+
// Query pricing for data transfer out to internet
|
|
59
|
+
const dataTransferPrice = await pricingClient.getPrice({
|
|
60
|
+
serviceCode: 'AmazonCloudFront',
|
|
61
|
+
region: this.normalizeRegion(region),
|
|
62
|
+
filters: [{ field: 'transferType', value: 'CloudFront to Internet' }],
|
|
63
|
+
});
|
|
64
|
+
// Query pricing for HTTP/HTTPS requests
|
|
65
|
+
const requestPrice = await pricingClient.getPrice({
|
|
66
|
+
serviceCode: 'AmazonCloudFront',
|
|
67
|
+
region: this.normalizeRegion(region),
|
|
68
|
+
filters: [{ field: 'requestType', value: 'HTTP-Requests' }],
|
|
69
|
+
});
|
|
70
|
+
if (dataTransferPrice === null || requestPrice === null) {
|
|
71
|
+
const assumptions = [
|
|
72
|
+
`Pricing data not available for CloudFront in region ${region}`,
|
|
73
|
+
`Would assume ${dataTransfer} GB of data transfer out to internet`,
|
|
74
|
+
`Would assume ${requestCount.toLocaleString()} HTTP/HTTPS requests per month`,
|
|
75
|
+
];
|
|
76
|
+
if (this.dataTransferGB !== undefined) {
|
|
77
|
+
assumptions.push(`Using custom data transfer assumption: ${dataTransfer} GB from configuration`);
|
|
78
|
+
}
|
|
79
|
+
if (this.requests !== undefined) {
|
|
80
|
+
assumptions.push(`Using custom request count assumption: ${requestCount.toLocaleString()} requests from configuration`);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
amount: 0,
|
|
84
|
+
currency: 'USD',
|
|
85
|
+
confidence: 'unknown',
|
|
86
|
+
assumptions,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
// Calculate costs
|
|
90
|
+
const dataTransferCost = dataTransfer * dataTransferPrice;
|
|
91
|
+
const requestCost = (requestCount / 10000) * requestPrice; // Pricing is per 10,000 requests
|
|
92
|
+
const totalCost = dataTransferCost + requestCost;
|
|
93
|
+
const assumptions = [
|
|
94
|
+
`Assumes ${dataTransfer} GB of data transfer out to internet`,
|
|
95
|
+
`Assumes ${requestCount.toLocaleString()} HTTP/HTTPS requests per month`,
|
|
96
|
+
];
|
|
97
|
+
if (this.dataTransferGB !== undefined) {
|
|
98
|
+
assumptions.push(`Using custom data transfer assumption: ${dataTransfer} GB from configuration`);
|
|
99
|
+
}
|
|
100
|
+
if (this.requests !== undefined) {
|
|
101
|
+
assumptions.push(`Using custom request count assumption: ${requestCount.toLocaleString()} requests from configuration`);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
amount: totalCost,
|
|
105
|
+
currency: 'USD',
|
|
106
|
+
confidence: 'medium',
|
|
107
|
+
assumptions,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
return {
|
|
112
|
+
amount: 0,
|
|
113
|
+
currency: 'USD',
|
|
114
|
+
confidence: 'unknown',
|
|
115
|
+
assumptions: [
|
|
116
|
+
`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`,
|
|
117
|
+
],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Normalizes AWS region code to AWS Pricing API region name.
|
|
123
|
+
*
|
|
124
|
+
* CloudFront is a global service, but pricing varies by region and the
|
|
125
|
+
* AWS Pricing API requires region names in specific format.
|
|
126
|
+
*
|
|
127
|
+
* @param region - AWS region code (e.g., 'us-east-1')
|
|
128
|
+
* @returns AWS Pricing API region name (e.g., 'US East (N. Virginia)')
|
|
129
|
+
*/
|
|
130
|
+
normalizeRegion(region) {
|
|
131
|
+
const regionMap = {
|
|
132
|
+
'us-east-1': 'US East (N. Virginia)',
|
|
133
|
+
'us-east-2': 'US East (Ohio)',
|
|
134
|
+
'us-west-1': 'US West (N. California)',
|
|
135
|
+
'us-west-2': 'US West (Oregon)',
|
|
136
|
+
'eu-west-1': 'EU (Ireland)',
|
|
137
|
+
'eu-west-2': 'EU (London)',
|
|
138
|
+
'eu-west-3': 'EU (Paris)',
|
|
139
|
+
'eu-central-1': 'EU (Frankfurt)',
|
|
140
|
+
'eu-north-1': 'EU (Stockholm)',
|
|
141
|
+
'ap-south-1': 'Asia Pacific (Mumbai)',
|
|
142
|
+
'ap-southeast-1': 'Asia Pacific (Singapore)',
|
|
143
|
+
'ap-southeast-2': 'Asia Pacific (Sydney)',
|
|
144
|
+
'ap-northeast-1': 'Asia Pacific (Tokyo)',
|
|
145
|
+
'ap-northeast-2': 'Asia Pacific (Seoul)',
|
|
146
|
+
};
|
|
147
|
+
return regionMap[region] || region;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exports.CloudFrontCalculator = CloudFrontCalculator;
|
|
151
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2xvdWRGcm9udENhbGN1bGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcHJpY2luZy9jYWxjdWxhdG9ycy9DbG91ZEZyb250Q2FsY3VsYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFHQTs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFhLG9CQUFvQjtJQVdaO0lBQ0E7SUFYRix3QkFBd0IsR0FBRyxHQUFHLENBQUM7SUFDL0IsZ0JBQWdCLEdBQUcsT0FBTyxDQUFDO0lBRTVDOzs7OztPQUtHO0lBQ0gsWUFDbUIsY0FBdUIsRUFDdkIsUUFBaUI7UUFEakIsbUJBQWMsR0FBZCxjQUFjLENBQVM7UUFDdkIsYUFBUSxHQUFSLFFBQVEsQ0FBUztJQUNqQyxDQUFDO0lBRUo7Ozs7O09BS0c7SUFDSCxRQUFRLENBQUMsWUFBb0I7UUFDM0IsT0FBTyxZQUFZLEtBQUssK0JBQStCLENBQUM7SUFDMUQsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7T0FlRztJQUNILEtBQUssQ0FBQyxhQUFhLENBQ2pCLFNBQXlCLEVBQ3pCLE1BQWMsRUFDZCxhQUE0QjtRQUU1QixNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsY0FBYyxJQUFJLElBQUksQ0FBQyx3QkFBd0IsQ0FBQztRQUMxRSxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztRQUU1RCxJQUFJLENBQUM7WUFDSCxrREFBa0Q7WUFDbEQsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLGFBQWEsQ0FBQyxRQUFRLENBQUM7Z0JBQ3JELFdBQVcsRUFBRSxrQkFBa0I7Z0JBQy9CLE1BQU0sRUFBRSxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQztnQkFDcEMsT0FBTyxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsY0FBYyxFQUFFLEtBQUssRUFBRSx3QkFBd0IsRUFBRSxDQUFDO2FBQ3RFLENBQUMsQ0FBQztZQUVILHdDQUF3QztZ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QVcsRUFBRSxZQUFZO1lBQ3pCLGNBQWMsRUFBRSxnQkFBZ0I7WUFDaEMsWUFBWSxFQUFFLGdCQUFnQjtZQUM5QixZQUFZLEVBQUUsdUJBQXVCO1lBQ3JDLGdCQUFnQixFQUFFLDBCQUEwQjtZQUM1QyxnQkFBZ0IsRUFBRSx1QkFBdUI7WUFDekMsZ0JBQWdCLEVBQUUsc0JBQXNCO1lBQ3hDLGdCQUFnQixFQUFFLHNCQUFzQjtTQUN6QyxDQUFDO1FBRUYsT0FBTyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksTUFBTSxDQUFDO0lBQ3JDLENBQUM7Q0FDRjtBQS9KRCxvREErSkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXNvdXJjZVdpdGhJZCB9IGZyb20gJy4uLy4uL2RpZmYvdHlwZXMnO1xuaW1wb3J0IHsgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciwgTW9udGhseUNvc3QsIFByaWNpbmdDbGllbnQgfSBmcm9tICcuLi90eXBlcyc7XG5cbi8qKlxuICogQ2FsY3VsYXRvciBmb3IgQVdTIENsb3VkRnJvbnQgZGlzdHJpYnV0aW9uIGNvc3RzLlxuICpcbiAqIEVzdGltYXRlcyBtb250aGx5IGNvc3RzIGJhc2VkIG9uIGRhdGEgdHJhbnNmZXIgYW5kIHJlcXVlc3Qgdm9sdW1lcy5cbiAqIENsb3VkRnJvbnQgcHJpY2luZyBpbmNsdWRlczpcbiAqIC0gRGF0YSB0cmFuc2ZlciBvdXQgdG8gaW50ZXJuZXQgKHBlciBHQilcbiAqIC0gSFRUUC9IVFRQUyByZXF1ZXN0cyAocGVyIDEwLDAwMCByZXF1ZXN0cylcbiAqXG4gKiBAc2VlIGh0dHBzOi8vYXdzLmFtYXpvbi5jb20vY2xvdWRmcm9udC9wcmljaW5nL1xuICovXG5leHBvcnQgY2xhc3MgQ2xvdWRGcm9udENhbGN1bGF0b3IgaW1wbGVtZW50cyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yIHtcbiAgcHJpdmF0ZSByZWFkb25seSBERUZBVUxUX0RBVEFfVFJBTlNGRVJfR0IgPSAxMDA7XG4gIHByaXZhdGUgcmVhZG9ubHkgREVGQVVMVF9SRVFVRVNUUyA9IDEwMDAwMDA7XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBDbG91ZEZyb250IGNvc3QgY2FsY3VsYXRvci5cbiAgICpcbiAgICogQHBhcmFtIGRhdGFUcmFuc2ZlckdCIC0gT3B0aW9uYWwgY3VzdG9tIGRhdGEgdHJhbnNmZXIgdm9sdW1lIGluIEdCIHBlciBtb250aFxuICAgKiBAcGFyYW0gcmVxdWVzdHMgLSBPcHRpb25hbCBjdXN0b20gcmVxdWVzdCBjb3VudCBwZXIgbW9udGhcbiAgICovXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgZGF0YVRyYW5zZmVyR0I/OiBudW1iZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSByZXF1ZXN0cz86IG51bWJlcixcbiAgKSB7fVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgdGhpcyBjYWxjdWxhdG9yIHN1cHBvcnRzIHRoZSBnaXZlbiByZXNvdXJjZSB0eXBlLlxuICAgKlxuICAgKiBAcGFyYW0gcmVzb3VyY2VUeXBlIC0gQ2xvdWRGb3JtYXRpb24gcmVzb3VyY2UgdHlwZVxuICAgKiBAcmV0dXJucyB0cnVlIGlmIHJlc291cmNlIHR5cGUgaXMgQVdTOjpDbG91ZEZyb250OjpEaXN0cmlidXRpb25cbiAgICovXG4gIHN1cHBvcnRzKHJlc291cmNlVHlwZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHJlc291cmNlVHlwZSA9PT0gJ0FXUzo6Q2xvdWRGcm9udDo6RGlzdHJpYnV0aW9uJztcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIG1vbnRobHkgY29zdCBmb3IgYSBDbG91ZEZyb250IGRpc3RyaWJ1dGlvbi5cbiAgICpcbiAgICogQ29zdCBjb21wb25lbnRzOlxuICAgKiAtIERhdGEgdHJhbnNmZXIgb3V0IHRvIGludGVybmV0IChiYXNlZCBvbiB2b2x1bWUgaW4gR0IpXG4gICAqIC0gSFRUUC9IVFRQUyByZXF1ZXN0cyAocGVyIDEwLDAwMCByZXF1ZXN0cylcbiAgICpcbiAgICogRGVmYXVsdCBhc3N1bXB0aW9uczpcbiAgICogLSAxMDAgR0IgZGF0YSB0cmFuc2ZlciBwZXIgbW9udGhcbiAgICogLSAxLDAwMCwwMDAgcmVxdWVzdHMgcGVyIG1vbnRoXG4gICAqXG4gICAqIEBwYXJhbSBfcmVzb3VyY2UgLSBDbG91ZEZvcm1hdGlvbiByZXNvdXJjZSAocHJvcGVydGllcyBub3QgdXNlZCBmb3IgQ2xvdWRGcm9udClcbiAgICogQHBhcmFtIHJlZ2lvbiAtIEFXUyByZWdpb24gZm9yIHByaWNpbmcgKENsb3VkRnJvbnQgaXMgZ2xvYmFsIGJ1dCBwcmljaW5nIHZhcmllcyBieSByZWdpb24pXG4gICAqIEBwYXJhbSBwcmljaW5nQ2xpZW50IC0gQ2xpZW50IGZvciBxdWVyeWluZyBBV1MgUHJpY2luZyBBUElcbiAgICogQHJldHVybnMgTW9udGhseSBjb3N0IGVzdGltYXRlIHdpdGggYXNzdW1wdGlvbnMgYW5kIGNvbmZpZGVuY2UgbGV2ZWxcbiAgICovXG4gIGFzeW5jIGNhbGN1bGF0ZUNvc3QoXG4gICAgX3Jlc291cmNlOiBSZXNvdXJjZVdpdGhJZCxcbiAgICByZWdpb246IHN0cmluZyxcbiAgICBwcmljaW5nQ2xpZW50OiBQcmljaW5nQ2xpZW50LFxuICApOiBQcm9taXNlPE1vbnRobHlDb3N0PiB7XG4gICAgY29uc3QgZGF0YVRyYW5zZmVyID0gdGhpcy5kYXRhVHJhbnNmZXJHQiA/PyB0aGlzLkRFRkFVTFRfREFUQV9UUkFOU0ZFUl9HQjtcbiAgICBjb25zdCByZXF1ZXN0Q291bnQgPSB0aGlzLnJlcXVlc3RzID8/IHRoaXMuREVGQVVMVF9SRVFVRVNUUztcblxuICAgIHRyeSB7XG4gICAgICAvLyBRdWVyeSBwcmljaW5nIGZvciBkYXRhIHRyYW5zZmVyIG91dCB0byBpbnRlcm5ldFxuICAgICAgY29uc3QgZGF0YVRyYW5zZmVyUHJpY2UgPSBhd2FpdCBwcmljaW5nQ2xpZW50LmdldFByaWNlKHtcbiAgICAgICAgc2VydmljZUNvZGU6ICdBbWF6b25DbG91ZEZyb250JyxcbiAgICAgICAgcmVnaW9uOiB0aGlzLm5vcm1hbGl6ZVJlZ2lvbihyZWdpb24pLFxuICAgICAgICBmaWx0ZXJzOiBbeyBmaWVsZDogJ3RyYW5zZmVyVHlwZScsIHZhbHVlOiAnQ2xvdWRGcm9udCB0byBJbnRlcm5ldCcgfV0sXG4gICAgICB9KTtcblxuICAgICAgLy8gUXVlcnkgcHJpY2luZyBmb3IgSFRUUC9IVFRQUyByZXF1ZXN0c1xuICAgICAgY29uc3QgcmVxdWVzdFByaWNlID0gYXdhaXQgcHJpY2luZ0NsaWVudC5nZXRQcmljZSh7XG4gICAgICAgIHNlcnZpY2VDb2RlOiAnQW1hem9uQ2xvdWRGcm9udCcsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW3sgZmllbGQ6ICdyZXF1ZXN0VHlwZScsIHZhbHVlOiAnSFRUUC1SZXF1ZXN0cycgfV0sXG4gICAgICB9KTtcblxuICAgICAgaWYgKGRhdGFUcmFuc2ZlclByaWNlID09PSBudWxsIHx8IHJlcXVlc3RQcmljZSA9PT0gbnVsbCkge1xuICAgICAgICBjb25zdCBhc3N1bXB0aW9ucyA9IFtcbiAgICAgICAgICBgUHJpY2luZyBkYXRhIG5vdCBhdmFpbGFibGUgZm9yIENsb3VkRnJvbnQgaW4gcmVnaW9uICR7cmVnaW9ufWAsXG4gICAgICAgICAgYFdvdWxkIGFzc3VtZSAke2RhdGFUcmFuc2Zlcn0gR0Igb2YgZGF0YSB0cmFuc2ZlciBvdXQgdG8gaW50ZXJuZXRgLFxuICAgICAgICAgIGBXb3VsZCBhc3N1bWUgJHtyZXF1ZXN0Q291bnQudG9Mb2NhbGVTdHJpbmcoKX0gSFRUUC9IVFRQUyByZXF1ZXN0cyBwZXIgbW9udGhgLFxuICAgICAgICBdO1xuXG4gICAgICAgIGlmICh0aGlzLmRhdGFUcmFuc2ZlckdCICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBhc3N1bXB0aW9ucy5wdXNoKFxuICAgICAgICAgICAgYFVzaW5nIGN1c3RvbSBkYXRhIHRyYW5zZmVyIGFzc3VtcHRpb246ICR7ZGF0YVRyYW5zZmVyfSBHQiBmcm9tIGNvbmZpZ3VyYXRpb25gLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMucmVxdWVzdHMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGFzc3VtcHRpb25zLnB1c2goXG4gICAgICAgICAgICBgVXNpbmcgY3VzdG9tIHJlcXVlc3QgY291bnQgYXNzdW1wdGlvbjogJHtyZXF1ZXN0Q291bnQudG9Mb2NhbGVTdHJpbmcoKX0gcmVxdWVzdHMgZnJvbSBjb25maWd1cmF0aW9uYCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgICBhc3N1bXB0aW9ucyxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgLy8gQ2FsY3VsYXRlIGNvc3RzXG4gICAgICBjb25zdCBkYXRhVHJhbnNmZXJDb3N0ID0gZGF0YVRyYW5zZmVyICogZGF0YVRyYW5zZmVyUHJpY2U7XG4gICAgICBjb25zdCByZXF1ZXN0Q29zdCA9IChyZXF1ZXN0Q291bnQgLyAxMDAwMCkgKiByZXF1ZXN0UHJpY2U7IC8vIFByaWNpbmcgaXMgcGVyIDEwLDAwMCByZXF1ZXN0c1xuXG4gICAgICBjb25zdCB0b3RhbENvc3QgPSBkYXRhVHJhbnNmZXJDb3N0ICsgcmVxdWVzdENvc3Q7XG5cbiAgICAgIGNvbnN0IGFzc3VtcHRpb25zID0gW1xuICAgICAgICBgQXNzdW1lcyAke2RhdGFUcmFuc2Zlcn0gR0Igb2YgZGF0YSB0cmFuc2ZlciBvdXQgdG8gaW50ZXJuZXRgLFxuICAgICAgICBgQXNzdW1lcyAke3JlcXVlc3RDb3VudC50b0xvY2FsZVN0cmluZygpfSBIVFRQL0hUVFBTIHJlcXVlc3RzIHBlciBtb250aGAsXG4gICAgICBdO1xuXG4gICAgICBpZiAodGhpcy5kYXRhVHJhbnNmZXJHQiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGFzc3VtcHRpb25zLnB1c2goXG4gICAgICAgICAgYFVzaW5nIGN1c3RvbSBkYXRhIHRyYW5zZmVyIGFzc3VtcHRpb246ICR7ZGF0YVRyYW5zZmVyfSBHQiBmcm9tIGNvbmZpZ3VyYXRpb25gLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMucmVxdWVzdHMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBhc3N1bXB0aW9ucy5wdXNoKFxuICAgICAgICAgIGBVc2luZyBjdXN0b20gcmVxdWVzdCBjb3VudCBhc3N1bXB0aW9uOiAke3JlcXVlc3RDb3VudC50b0xvY2FsZVN0cmluZygpfSByZXF1ZXN0cyBmcm9tIGNvbmZpZ3VyYXRpb25gLFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IHRvdGFsQ29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnbWVkaXVtJyxcbiAgICAgICAgYXNzdW1wdGlvbnMsXG4gICAgICB9O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgICAgY29uZmlkZW5jZTogJ3Vua25vd24nLFxuICAgICAgICBhc3N1bXB0aW9uczogW1xuICAgICAgICAgIGBGYWlsZWQgdG8gZmV0Y2ggcHJpY2luZzogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCxcbiAgICAgICAgXSxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIE5vcm1hbGl6ZXMgQVdTIHJlZ2lvbiBjb2RlIHRvIEFXUyBQcmljaW5nIEFQSSByZWdpb24gbmFtZS5cbiAgICpcbiAgICogQ2xvdWRGcm9udCBpcyBhIGdsb2JhbCBzZXJ2aWNlLCBidXQgcHJpY2luZyB2YXJpZXMgYnkgcmVnaW9uIGFuZCB0aGVcbiAgICogQVdTIFByaWNpbmcgQVBJIHJlcXVpcmVzIHJlZ2lvbiBuYW1lcyBpbiBzcGVjaWZpYyBmb3JtYXQuXG4gICAqXG4gICAqIEBwYXJhbSByZWdpb24gLSBBV1MgcmVnaW9uIGNvZGUgKGUuZy4sICd1cy1lYXN0LTEnKVxuICAgKiBAcmV0dXJucyBBV1MgUHJpY2luZyBBUEkgcmVnaW9uIG5hbWUgKGUuZy4sICdVUyBFYXN0IChOLiBWaXJnaW5pYSknKVxuICAgKi9cbiAgcHJpdmF0ZSBub3JtYWxpemVSZWdpb24ocmVnaW9uOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHJlZ2lvbk1hcDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICAgICd1cy1lYXN0LTEnOiAnVVMgRWFzdCAoTi4gVmlyZ2luaWEpJyxcbiAgICAgICd1cy1lYXN0LTInOiAnVVMgRWFzdCAoT2hpbyknLFxuICAgICAgJ3VzLXdlc3QtMSc6ICdVUyBXZXN0IChOLiBDYWxpZm9ybmlhKScsXG4gICAgICAndXMtd2VzdC0yJzogJ1VTIFdlc3QgKE9yZWdvbiknLFxuICAgICAgJ2V1LXdlc3QtMSc6ICdFVSAoSXJlbGFuZCknLFxuICAgICAgJ2V1LXdlc3QtMic6ICdFVSAoTG9uZG9uKScsXG4gICAgICAnZXUtd2VzdC0zJzogJ0VVIChQYXJpcyknLFxuICAgICAgJ2V1LWNlbnRyYWwtMSc6ICdFVSAoRnJhbmtmdXJ0KScsXG4gICAgICAnZXUtbm9ydGgtMSc6ICdFVSAoU3RvY2tob2xtKScsXG4gICAgICAnYXAtc291dGgtMSc6ICdBc2lhIFBhY2lmaWMgKE11bWJhaSknLFxuICAgICAgJ2FwLXNvdXRoZWFzdC0xJzogJ0FzaWEgUGFjaWZpYyAoU2luZ2Fwb3JlKScsXG4gICAgICAnYXAtc291dGhlYXN0LTInOiAnQXNpYSBQYWNpZmljIChTeWRuZXkpJyxcbiAgICAgICdhcC1ub3J0aGVhc3QtMSc6ICdBc2lhIFBhY2lmaWMgKFRva3lvKScsXG4gICAgICAnYXAtbm9ydGhlYXN0LTInOiAnQXNpYSBQYWNpZmljIChTZW91bCknLFxuICAgIH07XG5cbiAgICByZXR1cm4gcmVnaW9uTWFwW3JlZ2lvbl0gfHwgcmVnaW9uO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ResourceWithId } from '../../diff/types';
|
|
2
|
+
import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
|
|
3
|
+
export declare class DynamoDBCalculator implements ResourceCostCalculator {
|
|
4
|
+
supports(resourceType: string): boolean;
|
|
5
|
+
calculateCost(resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
|
|
6
|
+
private calculateOnDemandCost;
|
|
7
|
+
private calculateProvisionedCost;
|
|
8
|
+
private normalizeRegion;
|
|
9
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DynamoDBCalculator = void 0;
|
|
4
|
+
class DynamoDBCalculator {
|
|
5
|
+
supports(resourceType) {
|
|
6
|
+
return resourceType === 'AWS::DynamoDB::Table';
|
|
7
|
+
}
|
|
8
|
+
async calculateCost(resource, region, pricingClient) {
|
|
9
|
+
const billingMode = resource.properties.BillingMode || 'PROVISIONED';
|
|
10
|
+
if (billingMode === 'PAY_PER_REQUEST') {
|
|
11
|
+
return this.calculateOnDemandCost(resource, region, pricingClient);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
return this.calculateProvisionedCost(resource, region, pricingClient);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async calculateOnDemandCost(_resource, region, pricingClient) {
|
|
18
|
+
try {
|
|
19
|
+
// Default assumptions for on-demand mode
|
|
20
|
+
const assumedReadRequests = 10_000_000; // 10M read requests per month
|
|
21
|
+
const assumedWriteRequests = 1_000_000; // 1M write requests per month
|
|
22
|
+
const readCostPerMillion = await pricingClient.getPrice({
|
|
23
|
+
serviceCode: 'AmazonDynamoDB',
|
|
24
|
+
region: this.normalizeRegion(region),
|
|
25
|
+
filters: [
|
|
26
|
+
{ field: 'group', value: 'DDB-ReadUnits' },
|
|
27
|
+
{ field: 'groupDescription', value: 'OnDemand ReadRequestUnits' },
|
|
28
|
+
],
|
|
29
|
+
});
|
|
30
|
+
const writeCostPerMillion = await pricingClient.getPrice({
|
|
31
|
+
serviceCode: 'AmazonDynamoDB',
|
|
32
|
+
region: this.normalizeRegion(region),
|
|
33
|
+
filters: [
|
|
34
|
+
{ field: 'group', value: 'DDB-WriteUnits' },
|
|
35
|
+
{ field: 'groupDescription', value: 'OnDemand WriteRequestUnits' },
|
|
36
|
+
],
|
|
37
|
+
});
|
|
38
|
+
if (readCostPerMillion === null || writeCostPerMillion === null) {
|
|
39
|
+
return {
|
|
40
|
+
amount: 0,
|
|
41
|
+
currency: 'USD',
|
|
42
|
+
confidence: 'unknown',
|
|
43
|
+
assumptions: ['Pricing data not available for DynamoDB on-demand mode'],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const readCost = (assumedReadRequests / 1_000_000) * readCostPerMillion;
|
|
47
|
+
const writeCost = (assumedWriteRequests / 1_000_000) * writeCostPerMillion;
|
|
48
|
+
const monthlyCost = readCost + writeCost;
|
|
49
|
+
return {
|
|
50
|
+
amount: monthlyCost,
|
|
51
|
+
currency: 'USD',
|
|
52
|
+
confidence: 'medium',
|
|
53
|
+
assumptions: [
|
|
54
|
+
`Assumes ${assumedReadRequests.toLocaleString()} read requests per month`,
|
|
55
|
+
`Assumes ${assumedWriteRequests.toLocaleString()} write requests per month`,
|
|
56
|
+
'On-demand billing mode',
|
|
57
|
+
'Does not include storage costs or other features (streams, backups, etc.)',
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
return {
|
|
63
|
+
amount: 0,
|
|
64
|
+
currency: 'USD',
|
|
65
|
+
confidence: 'unknown',
|
|
66
|
+
assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async calculateProvisionedCost(resource, region, pricingClient) {
|
|
71
|
+
try {
|
|
72
|
+
const provisionedThroughput = resource.properties.ProvisionedThroughput;
|
|
73
|
+
const readCapacity = provisionedThroughput?.ReadCapacityUnits || 5;
|
|
74
|
+
const writeCapacity = provisionedThroughput?.WriteCapacityUnits || 5;
|
|
75
|
+
const readCostPerHour = await pricingClient.getPrice({
|
|
76
|
+
serviceCode: 'AmazonDynamoDB',
|
|
77
|
+
region: this.normalizeRegion(region),
|
|
78
|
+
filters: [
|
|
79
|
+
{ field: 'group', value: 'DDB-ReadUnits' },
|
|
80
|
+
{ field: 'groupDescription', value: 'Provisioned ReadCapacityUnit-Hrs' },
|
|
81
|
+
],
|
|
82
|
+
});
|
|
83
|
+
const writeCostPerHour = await pricingClient.getPrice({
|
|
84
|
+
serviceCode: 'AmazonDynamoDB',
|
|
85
|
+
region: this.normalizeRegion(region),
|
|
86
|
+
filters: [
|
|
87
|
+
{ field: 'group', value: 'DDB-WriteUnits' },
|
|
88
|
+
{ field: 'groupDescription', value: 'Provisioned WriteCapacityUnit-Hrs' },
|
|
89
|
+
],
|
|
90
|
+
});
|
|
91
|
+
if (readCostPerHour === null || writeCostPerHour === null) {
|
|
92
|
+
return {
|
|
93
|
+
amount: 0,
|
|
94
|
+
currency: 'USD',
|
|
95
|
+
confidence: 'unknown',
|
|
96
|
+
assumptions: ['Pricing data not available for DynamoDB provisioned mode'],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const hoursPerMonth = 730;
|
|
100
|
+
const readCost = readCapacity * hoursPerMonth * readCostPerHour;
|
|
101
|
+
const writeCost = writeCapacity * hoursPerMonth * writeCostPerHour;
|
|
102
|
+
const monthlyCost = readCost + writeCost;
|
|
103
|
+
return {
|
|
104
|
+
amount: monthlyCost,
|
|
105
|
+
currency: 'USD',
|
|
106
|
+
confidence: 'high',
|
|
107
|
+
assumptions: [
|
|
108
|
+
`${readCapacity} provisioned read capacity units`,
|
|
109
|
+
`${writeCapacity} provisioned write capacity units`,
|
|
110
|
+
`Assumes ${hoursPerMonth} hours per month (24/7 operation)`,
|
|
111
|
+
'Provisioned billing mode',
|
|
112
|
+
'Does not include storage costs or other features (streams, backups, etc.)',
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
return {
|
|
118
|
+
amount: 0,
|
|
119
|
+
currency: 'USD',
|
|
120
|
+
confidence: 'unknown',
|
|
121
|
+
assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
normalizeRegion(region) {
|
|
126
|
+
const regionMap = {
|
|
127
|
+
'us-east-1': 'US East (N. Virginia)',
|
|
128
|
+
'us-east-2': 'US East (Ohio)',
|
|
129
|
+
'us-west-1': 'US West (N. California)',
|
|
130
|
+
'us-west-2': 'US West (Oregon)',
|
|
131
|
+
'eu-west-1': 'EU (Ireland)',
|
|
132
|
+
'eu-west-2': 'EU (London)',
|
|
133
|
+
'eu-west-3': 'EU (Paris)',
|
|
134
|
+
'eu-central-1': 'EU (Frankfurt)',
|
|
135
|
+
'eu-north-1': 'EU (Stockholm)',
|
|
136
|
+
'ap-south-1': 'Asia Pacific (Mumbai)',
|
|
137
|
+
'ap-southeast-1': 'Asia Pacific (Singapore)',
|
|
138
|
+
'ap-southeast-2': 'Asia Pacific (Sydney)',
|
|
139
|
+
'ap-northeast-1': 'Asia Pacific (Tokyo)',
|
|
140
|
+
'ap-northeast-2': 'Asia Pacific (Seoul)',
|
|
141
|
+
};
|
|
142
|
+
return regionMap[region] || region;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.DynamoDBCalculator = DynamoDBCalculator;
|
|
146
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRHluYW1vREJDYWxjdWxhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ByaWNpbmcvY2FsY3VsYXRvcnMvRHluYW1vREJDYWxjdWxhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUdBLE1BQWEsa0JBQWtCO0lBQzdCLFFBQVEsQ0FBQyxZQUFvQjtRQUMzQixPQUFPLFlBQVksS0FBSyxzQkFBc0IsQ0FBQztJQUNqRCxDQUFDO0lBRUQsS0FBSyxDQUFDLGFBQWEsQ0FDakIsUUFBd0IsRUFDeEIsTUFBYyxFQUNkLGFBQTRCO1FBRTVCLE1BQU0sV0FBVyxHQUFJLFFBQVEsQ0FBQyxVQUFVLENBQUMsV0FBc0IsSUFBSSxhQUFhLENBQUM7UUFFakYsSUFBSSxXQUFXLEtBQUssaUJBQWlCLEVBQUUsQ0FBQztZQUN0QyxPQUFPLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBQ3JFLENBQUM7YUFBTSxDQUFDO1lBQ04sT0FBTyxJQUFJLENBQUMsd0JBQXdCLENBQUMsUUFBUSxFQUFFLE1BQU0sRUFBRSxhQUFhLENBQUMsQ0FBQztRQUN4RSxDQUFDO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxxQkFBcUIsQ0FDakMsU0FBeUIsRUFDekIsTUFBYyxFQUNkLGFBQTRCO1FBRTVCLElBQUksQ0FBQztZQUNILHlDQUF5QztZQUN6QyxNQUFNLG1CQUFtQixHQUFHLFVBQVUsQ0FBQyxDQUFDLDhCQUE4QjtZQUN0RSxNQUFNLG9CQUFvQixHQUFHLFNBQVMsQ0FBQyxDQUFDLDhCQUE4QjtZQUV0RSxNQUFNLGtCQUFrQixHQUFHLE1BQU0sYUFBYSxDQUFDLFFBQVEsQ0FBQztnQkFDdEQsV0FBVyxFQUFFLGdCQUFnQjtnQkFDN0IsTUFBTSxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDO2dCQUNwQyxPQUFPLEVBQUU7b0JBQ1AsRUFBRSxLQUFLLEVBQUUs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QUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO2FBQ3BHLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVPLGVBQWUsQ0FBQyxNQUFjO1FBQ3BDLE1BQU0sU0FBUyxHQUEyQjtZQUN4QyxXQUFXLEVBQUUsdUJBQXVCO1lBQ3BDLFdBQVcsRUFBRSxnQkFBZ0I7WUFDN0IsV0FBVyxFQUFFLHlCQUF5QjtZQUN0QyxXQUFXLEVBQUUsa0JBQWtCO1lBQy9CLFdBQVcsRUFBRSxjQUFjO1lBQzNCLFdBQVcsRUFBRSxhQUFhO1lBQzFCLFdBQVcsRUFBRSxZQUFZO1lBQ3pCLGNBQWMsRUFBRSxnQkFBZ0I7WUFDaEMsWUFBWSxFQUFFLGdCQUFnQjtZQUM5QixZQUFZLEVBQUUsdUJBQXVCO1lBQ3JDLGdCQUFnQixFQUFFLDBCQUEwQjtZQUM1QyxnQkFBZ0IsRUFBRSx1QkFBdUI7WUFDekMsZ0JBQWdCLEVBQUUsc0JBQXNCO1lBQ3hDLGdCQUFnQixFQUFFLHNCQUFzQjtTQUN6QyxDQUFDO1FBRUYsT0FBTyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksTUFBTSxDQUFDO0lBQ3JDLENBQUM7Q0FDRjtBQXJLRCxnREFxS0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXNvdXJjZVdpdGhJZCB9IGZyb20gJy4uLy4uL2RpZmYvdHlwZXMnO1xuaW1wb3J0IHsgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciwgTW9udGhseUNvc3QsIFByaWNpbmdDbGllbnQgfSBmcm9tICcuLi90eXBlcyc7XG5cbmV4cG9ydCBjbGFzcyBEeW5hbW9EQkNhbGN1bGF0b3IgaW1wbGVtZW50cyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yIHtcbiAgc3VwcG9ydHMocmVzb3VyY2VUeXBlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gcmVzb3VyY2VUeXBlID09PSAnQVdTOjpEeW5hbW9EQjo6VGFibGUnO1xuICB9XG5cbiAgYXN5bmMgY2FsY3VsYXRlQ29zdChcbiAgICByZXNvdXJjZTogUmVzb3VyY2VXaXRoSWQsXG4gICAgcmVnaW9uOiBzdHJpbmcsXG4gICAgcHJpY2luZ0NsaWVudDogUHJpY2luZ0NsaWVudCxcbiAgKTogUHJvbWlzZTxNb250aGx5Q29zdD4ge1xuICAgIGNvbnN0IGJpbGxpbmdNb2RlID0gKHJlc291cmNlLnByb3BlcnRpZXMuQmlsbGluZ01vZGUgYXMgc3RyaW5nKSB8fCAnUFJPVklTSU9ORUQnO1xuXG4gICAgaWYgKGJpbGxpbmdNb2RlID09PSAnUEFZX1BFUl9SRVFVRVNUJykge1xuICAgICAgcmV0dXJuIHRoaXMuY2FsY3VsYXRlT25EZW1hbmRDb3N0KHJlc291cmNlLCByZWdpb24sIHByaWNpbmdDbGllbnQpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gdGhpcy5jYWxjdWxhdGVQcm92aXNpb25lZENvc3QocmVzb3VyY2UsIHJlZ2lvbiwgcHJpY2luZ0NsaWVudCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjYWxjdWxhdGVPbkRlbWFuZENvc3QoXG4gICAgX3Jlc291cmNlOiBSZXNvdXJjZVdpdGhJZCxcbiAgICByZWdpb246IHN0cmluZyxcbiAgICBwcmljaW5nQ2xpZW50OiBQcmljaW5nQ2xpZW50LFxuICApOiBQcm9taXNlPE1vbnRobHlDb3N0PiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIERlZmF1bHQgYXNzdW1wdGlvbnMgZm9yIG9uLWRlbWFuZCBtb2RlXG4gICAgICBjb25zdCBhc3N1bWVkUmVhZFJlcXVlc3RzID0gMTBfMDAwXzAwMDsgLy8gMTBNIHJlYWQgcmVxdWVzdHMgcGVyIG1vbnRoXG4gICAgICBjb25zdCBhc3N1bWVkV3JpdGVSZXF1ZXN0cyA9IDFfMDAwXzAwMDsgLy8gMU0gd3JpdGUgcmVxdWVzdHMgcGVyIG1vbnRoXG5cbiAgICAgIGNvbnN0IHJlYWRDb3N0UGVyTWlsbGlvbiA9IGF3YWl0IHByaWNpbmdDbGllbnQuZ2V0UHJpY2Uoe1xuICAgICAgICBzZXJ2aWNlQ29kZTogJ0FtYXpvbkR5bmFtb0RCJyxcbiAgICAgICAgcmVnaW9uOiB0aGlzLm5vcm1hbGl6ZVJlZ2lvbihyZWdpb24pLFxuICAgICAgICBmaWx0ZXJzOiBbXG4gICAgICAgICAgeyBmaWVsZDogJ2dyb3VwJywgdmFsdWU6ICdEREItUmVhZFVuaXRzJyB9LFxuICAgICAgICAgIHsgZmllbGQ6ICdncm91cERlc2NyaXB0aW9uJywgdmFsdWU6ICdPbkRlbWFuZCBSZWFkUmVxdWVzdFVuaXRzJyB9LFxuICAgICAgICBdLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IHdyaXRlQ29zdFBlck1pbGxpb24gPSBhd2FpdCBwcmljaW5nQ2xpZW50LmdldFByaWNlKHtcbiAgICAgICAgc2VydmljZUNvZGU6ICdBbWF6b25EeW5hbW9EQicsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW1xuICAgICAgICAgIHsgZmllbGQ6ICdncm91cCcsIHZhbHVlOiAnRERCLVdyaXRlVW5pdHMnIH0sXG4gICAgICAgICAgeyBmaWVsZDogJ2dyb3VwRGVzY3JpcHRpb24nLCB2YWx1ZTogJ09uRGVtYW5kIFdyaXRlUmVxdWVzdFVuaXRzJyB9LFxuICAgICAgICBdLFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChyZWFkQ29zdFBlck1pbGxpb24gPT09IG51bGwgfHwgd3JpdGVDb3N0UGVyTWlsbGlvbiA9PT0gbnVsbCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgICAgY29uZmlkZW5jZTogJ3Vua25vd24nLFxuICAgICAgICAgIGFzc3VtcHRpb25zOiBbJ1ByaWNpbmcgZGF0YSBub3QgYXZhaWxhYmxlIGZvciBEeW5hbW9EQiBvbi1kZW1hbmQgbW9kZSddLFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBjb25zdCByZWFkQ29zdCA9IChhc3N1bWVkUmVhZFJlcXVlc3RzIC8gMV8wMDBfMDAwKSAqIHJlYWRDb3N0UGVyTWlsbGlvbjtcbiAgICAgIGNvbnN0IHdyaXRlQ29zdCA9IChhc3N1bWVkV3JpdGVSZXF1ZXN0cyAvIDFfMDAwXzAwMCkgKiB3cml0ZUNvc3RQZXJNaWxsaW9uO1xuICAgICAgY29uc3QgbW9udGhseUNvc3QgPSByZWFkQ29zdCArIHdyaXRlQ29zdDtcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiBtb250aGx5Q29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnbWVkaXVtJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtcbiAgICAgICAgICBgQXNzdW1lcyAke2Fzc3VtZWRSZWFkUmVxdWVzdHMudG9Mb2NhbGVTdHJpbmcoKX0gcmVhZCByZXF1ZXN0cyBwZXIgbW9udGhgLFxuICAgICAgICAgIGBBc3N1bWVzICR7YXNzdW1lZFdyaXRlUmVxdWVzdHMudG9Mb2NhbGVTdHJpbmcoKX0gd3JpdGUgcmVxdWVzdHMgcGVyIG1vbnRoYCxcbiAgICAgICAgICAnT24tZGVtYW5kIGJpbGxpbmcgbW9kZScsXG4gICAgICAgICAgJ0RvZXMgbm90IGluY2x1ZGUgc3RvcmFnZSBjb3N0cyBvciBvdGhlciBmZWF0dXJlcyAoc3RyZWFtcywgYmFja3VwcywgZXRjLiknLFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtgRmFpbGVkIHRvIGZldGNoIHByaWNpbmc6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWBdLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGNhbGN1bGF0ZVByb3Zpc2lvbmVkQ29zdChcbiAgICByZXNvdXJjZTogUmVzb3VyY2VXaXRoSWQsXG4gICAgcmVnaW9uOiBzdHJpbmcsXG4gICAgcHJpY2luZ0NsaWVudDogUHJpY2luZ0NsaWVudCxcbiAgKTogUHJvbWlzZTxNb250aGx5Q29zdD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBwcm92aXNpb25lZFRocm91Z2hwdXQgPSByZXNvdXJjZS5wcm9wZXJ0aWVzLlByb3Zpc2lvbmVkVGhyb3VnaHB1dCBhcyBhbnk7XG4gICAgICBjb25zdCByZWFkQ2FwYWNpdHkgPSBwcm92aXNpb25lZFRocm91Z2hwdXQ/LlJlYWRDYXBhY2l0eVVuaXRzIHx8IDU7XG4gICAgICBjb25zdCB3cml0ZUNhcGFjaXR5ID0gcHJvdmlzaW9uZWRUaHJvdWdocHV0Py5Xcml0ZUNhcGFjaXR5VW5pdHMgfHwgNTtcblxuICAgICAgY29uc3QgcmVhZENvc3RQZXJIb3VyID0gYXdhaXQgcHJpY2luZ0NsaWVudC5nZXRQcmljZSh7XG4gICAgICAgIHNlcnZpY2VDb2RlOiAnQW1hem9uRHluYW1vREInLFxuICAgICAgICByZWdpb246IHRoaXMubm9ybWFsaXplUmVnaW9uKHJlZ2lvbiksXG4gICAgICAgIGZpbHRlcnM6IFtcbiAgICAgICAgICB7IGZpZWxkOiAnZ3JvdXAnLCB2YWx1ZTogJ0REQi1SZWFkVW5pdHMnIH0sXG4gICAgICAgICAgeyBmaWVsZDogJ2dyb3VwRGVzY3JpcHRpb24nLCB2YWx1ZTogJ1Byb3Zpc2lvbmVkIFJlYWRDYXBhY2l0eVVuaXQtSHJzJyB9LFxuICAgICAgICBdLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IHdyaXRlQ29zdFBlckhvdXIgPSBhd2FpdCBwcmljaW5nQ2xpZW50LmdldFByaWNlKHtcbiAgICAgICAgc2VydmljZUNvZGU6ICdBbWF6b25EeW5hbW9EQicsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW1xuICAgICAgICAgIHsgZmllbGQ6ICdncm91cCcsIHZhbHVlOiAnRERCLVdyaXRlVW5pdHMnIH0sXG4gICAgICAgICAgeyBmaWVsZDogJ2dyb3VwRGVzY3JpcHRpb24nLCB2YWx1ZTogJ1Byb3Zpc2lvbmVkIFdyaXRlQ2FwYWNpdHlVbml0LUhycycgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAocmVhZENvc3RQZXJIb3VyID09PSBudWxsIHx8IHdyaXRlQ29zdFBlckhvdXIgPT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgICBhc3N1bXB0aW9uczogWydQcmljaW5nIGRhdGEgbm90IGF2YWlsYWJsZSBmb3IgRHluYW1vREIgcHJvdmlzaW9uZWQgbW9kZSddLFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBob3Vyc1Blck1vbnRoID0gNzMwO1xuICAgICAgY29uc3QgcmVhZENvc3QgPSByZWFkQ2FwYWNpdHkgKiBob3Vyc1Blck1vbnRoICogcmVhZENvc3RQZXJIb3VyO1xuICAgICAgY29uc3Qgd3JpdGVDb3N0ID0gd3JpdGVDYXBhY2l0eSAqIGhvdXJzUGVyTW9udGggKiB3cml0ZUNvc3RQZXJIb3VyO1xuICAgICAgY29uc3QgbW9udGhseUNvc3QgPSByZWFkQ29zdCArIHdyaXRlQ29zdDtcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiBtb250aGx5Q29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnaGlnaCcsXG4gICAgICAgIGFzc3VtcHRpb25zOiBbXG4gICAgICAgICAgYCR7cmVhZENhcGFjaXR5fSBwcm92aXNpb25lZCByZWFkIGNhcGFjaXR5IHVuaXRzYCxcbiAgICAgICAgICBgJHt3cml0ZUNhcGFjaXR5fSBwcm92aXNpb25lZCB3cml0ZSBjYXBhY2l0eSB1bml0c2AsXG4gICAgICAgICAgYEFzc3VtZXMgJHtob3Vyc1Blck1vbnRofSBob3VycyBwZXIgbW9udGggKDI0Lzcgb3BlcmF0aW9uKWAsXG4gICAgICAgICAgJ1Byb3Zpc2lvbmVkIGJpbGxpbmcgbW9kZScsXG4gICAgICAgICAgJ0RvZXMgbm90IGluY2x1ZGUgc3RvcmFnZSBjb3N0cyBvciBvdGhlciBmZWF0dXJlcyAoc3RyZWFtcywgYmFja3VwcywgZXRjLiknLFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtgRmFpbGVkIHRvIGZldGNoIHByaWNpbmc6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWBdLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG5vcm1hbGl6ZVJlZ2lvbihyZWdpb246IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgcmVnaW9uTWFwOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgICAgJ3VzLWVhc3QtMSc6ICdVUyBFYXN0IChOLiBWaXJnaW5pYSknLFxuICAgICAgJ3VzLWVhc3QtMic6ICdVUyBFYXN0IChPaGlvKScsXG4gICAgICAndXMtd2VzdC0xJzogJ1VTIFdlc3QgKE4uIENhbGlmb3JuaWEpJyxcbiAgICAgICd1cy13ZXN0LTInOiAnVVMgV2VzdCAoT3JlZ29uKScsXG4gICAgICAnZXUtd2VzdC0xJzogJ0VVIChJcmVsYW5kKScsXG4gICAgICAnZXUtd2VzdC0yJzogJ0VVIChMb25kb24pJyxcbiAgICAgICdldS13ZXN0LTMnOiAnRVUgKFBhcmlzKScsXG4gICAgICAnZXUtY2VudHJhbC0xJzogJ0VVIChGcmFua2Z1cnQpJyxcbiAgICAgICdldS1ub3J0aC0xJzogJ0VVIChTdG9ja2hvbG0pJyxcbiAgICAgICdhcC1zb3V0aC0xJzogJ0FzaWEgUGFjaWZpYyAoTXVtYmFpKScsXG4gICAgICAnYXAtc291dGhlYXN0LTEnOiAnQXNpYSBQYWNpZmljIChTaW5nYXBvcmUpJyxcbiAgICAgICdhcC1zb3V0aGVhc3QtMic6ICdBc2lhIFBhY2lmaWMgKFN5ZG5leSknLFxuICAgICAgJ2FwLW5vcnRoZWFzdC0xJzogJ0FzaWEgUGFjaWZpYyAoVG9reW8pJyxcbiAgICAgICdhcC1ub3J0aGVhc3QtMic6ICdBc2lhIFBhY2lmaWMgKFNlb3VsKScsXG4gICAgfTtcblxuICAgIHJldHVybiByZWdpb25NYXBbcmVnaW9uXSB8fCByZWdpb247XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ResourceWithId } from '../../diff/types';
|
|
2
|
+
import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
|
|
3
|
+
export declare class EC2Calculator implements ResourceCostCalculator {
|
|
4
|
+
supports(resourceType: string): boolean;
|
|
5
|
+
calculateCost(resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
|
|
6
|
+
private normalizeRegion;
|
|
7
|
+
}
|