cdk-cost-analyzer 0.1.39 → 0.1.41

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 (35) hide show
  1. package/.cdk-cost-analyzer-cache/metadata.json +8 -8
  2. package/.husky/pre-commit +6 -0
  3. package/dist/action/136.index.js +1 -1
  4. package/dist/action/762.index.js +1 -1
  5. package/dist/action/998.index.js +1 -1
  6. package/dist/action/config/types.d.ts +50 -0
  7. package/dist/action/index.js +3 -3
  8. package/dist/action/pricing/calculators/AuroraServerlessCalculator.d.ts +20 -0
  9. package/dist/action/pricing/calculators/EKSCalculator.d.ts +8 -0
  10. package/dist/action/pricing/calculators/KinesisCalculator.d.ts +27 -0
  11. package/dist/action/pricing/calculators/Route53Calculator.d.ts +18 -0
  12. package/dist/action/pricing/calculators/TransitGatewayCalculator.d.ts +16 -0
  13. package/dist/action/reporter/index.d.ts +1 -0
  14. package/dist/action/reporter/markdownUtils.d.ts +30 -0
  15. package/dist/config/types.d.ts +50 -0
  16. package/dist/config/types.js +1 -1
  17. package/dist/pricing/PricingService.js +11 -1
  18. package/dist/pricing/calculators/AuroraServerlessCalculator.d.ts +20 -0
  19. package/dist/pricing/calculators/AuroraServerlessCalculator.js +92 -0
  20. package/dist/pricing/calculators/EKSCalculator.d.ts +8 -0
  21. package/dist/pricing/calculators/EKSCalculator.js +46 -0
  22. package/dist/pricing/calculators/KinesisCalculator.d.ts +27 -0
  23. package/dist/pricing/calculators/KinesisCalculator.js +140 -0
  24. package/dist/pricing/calculators/Route53Calculator.d.ts +18 -0
  25. package/dist/pricing/calculators/Route53Calculator.js +99 -0
  26. package/dist/pricing/calculators/TransitGatewayCalculator.d.ts +16 -0
  27. package/dist/pricing/calculators/TransitGatewayCalculator.js +97 -0
  28. package/dist/releasetag.txt +1 -1
  29. package/dist/reporter/Reporter.js +94 -56
  30. package/dist/reporter/SingleTemplateReporter.js +49 -21
  31. package/dist/reporter/index.d.ts +1 -0
  32. package/dist/reporter/index.js +8 -2
  33. package/dist/reporter/markdownUtils.d.ts +30 -0
  34. package/dist/reporter/markdownUtils.js +93 -0
  35. package/package.json +2 -2
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KinesisCalculator = void 0;
4
+ const RegionMapper_1 = require("../RegionMapper");
5
+ class KinesisCalculator {
6
+ customShardCount;
7
+ customIngestionGB;
8
+ customRetrievalGB;
9
+ customFirehoseGB;
10
+ customKPUs;
11
+ HOURS_PER_MONTH = 730;
12
+ // Data Streams - Provisioned
13
+ DEFAULT_SHARD_COUNT = 2;
14
+ FALLBACK_SHARD_PRICE = 0.015;
15
+ // Data Streams - On-Demand
16
+ DEFAULT_INGESTION_GB = 1000;
17
+ DEFAULT_RETRIEVAL_GB = 2000;
18
+ FALLBACK_INGESTION_PRICE = 0.040;
19
+ FALLBACK_RETRIEVAL_PRICE = 0.015;
20
+ // Firehose
21
+ DEFAULT_FIREHOSE_GB = 1000;
22
+ FALLBACK_FIREHOSE_PRICE = 0.029;
23
+ // Analytics
24
+ DEFAULT_KPUS = 2;
25
+ FALLBACK_KPU_PRICE = 0.11;
26
+ constructor(customShardCount, customIngestionGB, customRetrievalGB, customFirehoseGB, customKPUs) {
27
+ this.customShardCount = customShardCount;
28
+ this.customIngestionGB = customIngestionGB;
29
+ this.customRetrievalGB = customRetrievalGB;
30
+ this.customFirehoseGB = customFirehoseGB;
31
+ this.customKPUs = customKPUs;
32
+ }
33
+ supports(resourceType) {
34
+ return (resourceType === 'AWS::Kinesis::Stream' ||
35
+ resourceType === 'AWS::KinesisFirehose::DeliveryStream' ||
36
+ resourceType === 'AWS::KinesisAnalyticsV2::Application');
37
+ }
38
+ async calculateCost(resource, region, pricingClient) {
39
+ try {
40
+ switch (resource.type) {
41
+ case 'AWS::Kinesis::Stream':
42
+ return await this.calculateDataStreamCost(resource, region, pricingClient);
43
+ case 'AWS::KinesisFirehose::DeliveryStream':
44
+ return this.calculateFirehoseCost();
45
+ case 'AWS::KinesisAnalyticsV2::Application':
46
+ return this.calculateAnalyticsCost();
47
+ default:
48
+ return {
49
+ amount: 0,
50
+ currency: 'USD',
51
+ confidence: 'unknown',
52
+ assumptions: [`Unsupported Kinesis resource type: ${resource.type}`],
53
+ };
54
+ }
55
+ }
56
+ catch (error) {
57
+ return {
58
+ amount: 0,
59
+ currency: 'USD',
60
+ confidence: 'unknown',
61
+ assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
62
+ };
63
+ }
64
+ }
65
+ async calculateDataStreamCost(resource, region, pricingClient) {
66
+ const props = resource.properties || {};
67
+ const streamModeDetails = props.StreamModeDetails;
68
+ const streamMode = streamModeDetails?.StreamMode || 'PROVISIONED';
69
+ if (streamMode === 'ON_DEMAND') {
70
+ return this.calculateOnDemandStreamCost();
71
+ }
72
+ const shardCount = this.customShardCount
73
+ ?? props.ShardCount
74
+ ?? this.DEFAULT_SHARD_COUNT;
75
+ const shardPrice = await pricingClient.getPrice({
76
+ serviceCode: 'AmazonKinesis',
77
+ region: (0, RegionMapper_1.normalizeRegion)(region),
78
+ filters: [
79
+ { field: 'productFamily', value: 'Kinesis Streams' },
80
+ { field: 'usagetype', value: 'shardHour-Provisioned' },
81
+ ],
82
+ });
83
+ const rate = shardPrice ?? this.FALLBACK_SHARD_PRICE;
84
+ const monthlyCost = shardCount * rate * this.HOURS_PER_MONTH;
85
+ return {
86
+ amount: monthlyCost,
87
+ currency: 'USD',
88
+ confidence: shardPrice !== null ? 'high' : 'medium',
89
+ assumptions: [
90
+ `Provisioned mode: ${shardCount} shards × $${rate.toFixed(4)}/shard-hour × ${this.HOURS_PER_MONTH}h = $${monthlyCost.toFixed(2)}/month`,
91
+ ...(shardPrice === null ? [`Using fallback pricing (API data not available for region ${region})`] : []),
92
+ ],
93
+ };
94
+ }
95
+ calculateOnDemandStreamCost() {
96
+ const ingestionGB = this.customIngestionGB ?? this.DEFAULT_INGESTION_GB;
97
+ const retrievalGB = this.customRetrievalGB ?? this.DEFAULT_RETRIEVAL_GB;
98
+ const ingestionCost = ingestionGB * this.FALLBACK_INGESTION_PRICE;
99
+ const retrievalCost = retrievalGB * this.FALLBACK_RETRIEVAL_PRICE;
100
+ const totalCost = ingestionCost + retrievalCost;
101
+ return {
102
+ amount: totalCost,
103
+ currency: 'USD',
104
+ confidence: 'medium',
105
+ assumptions: [
106
+ `On-demand mode`,
107
+ `Ingestion: ${ingestionGB} GB × $${this.FALLBACK_INGESTION_PRICE}/GB = $${ingestionCost.toFixed(2)}/month`,
108
+ `Retrieval: ${retrievalGB} GB × $${this.FALLBACK_RETRIEVAL_PRICE}/GB = $${retrievalCost.toFixed(2)}/month`,
109
+ ],
110
+ };
111
+ }
112
+ calculateFirehoseCost() {
113
+ const dataGB = this.customFirehoseGB ?? this.DEFAULT_FIREHOSE_GB;
114
+ const monthlyCost = dataGB * this.FALLBACK_FIREHOSE_PRICE;
115
+ return {
116
+ amount: monthlyCost,
117
+ currency: 'USD',
118
+ confidence: 'medium',
119
+ assumptions: [
120
+ `Firehose ingestion: ${dataGB} GB × $${this.FALLBACK_FIREHOSE_PRICE}/GB = $${monthlyCost.toFixed(2)}/month`,
121
+ 'Does not include format conversion or VPC delivery costs',
122
+ ],
123
+ };
124
+ }
125
+ calculateAnalyticsCost() {
126
+ const kpus = this.customKPUs ?? this.DEFAULT_KPUS;
127
+ const monthlyCost = kpus * this.FALLBACK_KPU_PRICE * this.HOURS_PER_MONTH;
128
+ return {
129
+ amount: monthlyCost,
130
+ currency: 'USD',
131
+ confidence: 'medium',
132
+ assumptions: [
133
+ `Kinesis Analytics: ${kpus} KPUs × $${this.FALLBACK_KPU_PRICE}/KPU-hour × ${this.HOURS_PER_MONTH}h = $${monthlyCost.toFixed(2)}/month`,
134
+ '1 KPU = 1 vCPU + 4 GB memory',
135
+ ],
136
+ };
137
+ }
138
+ }
139
+ exports.KinesisCalculator = KinesisCalculator;
140
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiS2luZXNpc0NhbGN1bGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcHJpY2luZy9jYWxjdWxhdG9ycy9LaW5lc2lzQ2FsY3VsYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFFQSxrREFBa0Q7QUFFbEQsTUFBYSxpQkFBaUI7SUFzQlQ7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQXpCRixlQUFlLEdBQUcsR0FBRyxDQUFDO0lBRXZDLDZCQUE2QjtJQUNaLG1CQUFtQixHQUFHLENBQUMsQ0FBQztJQUN4QixvQkFBb0IsR0FBRyxLQUFLLENBQUM7SUFFOUMsMkJBQTJCO0lBQ1Ysb0JBQW9CLEdBQUcsSUFBSSxDQUFDO0lBQzVCLG9CQUFvQixHQUFHLElBQUksQ0FBQztJQUM1Qix3QkFBd0IsR0FBRyxLQUFLLENBQUM7SUFDakMsd0JBQXdCLEdBQUcsS0FBSyxDQUFDO0lBRWxELFdBQVc7SUFDTSxtQkFBbUIsR0FBRyxJQUFJLENBQUM7SUFDM0IsdUJBQXVCLEdBQUcsS0FBSyxDQUFDO0lBRWpELFlBQVk7SUFDSyxZQUFZLEdBQUcsQ0FBQyxDQUFDO0lBQ2pCLGtCQUFrQixHQUFHLElBQUksQ0FBQztJQUUzQyxZQUNtQixnQkFBeUIsRUFDekIsaUJBQTBCLEVBQzFCLGlCQUEwQixFQUMxQixnQkFBeUIsRUFDekIsVUFBbUI7UUFKbkIscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFTO1FBQ3pCLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBUztRQUMxQixzQkFBaUIsR0FBakIsaUJBQWlCLENBQVM7UUFDMUIscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFTO1FBQ3pCLGVBQVUsR0FBVixVQUFVLENBQVM7SUFDbkMsQ0FBQztJQUVKLFFBQVEsQ0FBQyxZQUFvQjtRQUMzQixPQUFPLENBQ0wsWUFBWSxLQUFLLHNCQUFzQjtZQUN2QyxZQUFZLEtBQUssc0NBQXNDO1lBQ3ZELFlBQVksS0FBSyxzQ0FBc0MsQ0FDeEQsQ0FBQztJ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VyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsUUFBUTtnQkFDM0csMERBQTBEO2FBQzNEO1NBQ0YsQ0FBQztJQUNKLENBQUM7SUFFTyxzQkFBc0I7UUFDNUIsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFVBQVUsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDO1FBQ2xELE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQztRQUUxRSxPQUFPO1lBQ0wsTUFBTSxFQUFFLFdBQVc7WUFDbkIsUUFBUSxFQUFFLEtBQUs7WUFDZixVQUFVLEVBQUUsUUFBUTtZQUNwQixXQUFXLEVBQUU7Z0JBQ1gsc0JBQXNCLElBQUksWUFBWSxJQUFJLENBQUMsa0JBQWtCLGVBQWUsSUFBSSxDQUFDLGVBQWUsUUFBUSxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxRQUFRO2dCQUN0SSw4QkFBOEI7YUFDL0I7U0FDRixDQUFDO0lBQ0osQ0FBQztDQUNGO0FBN0pELDhDQTZKQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJlc291cmNlV2l0aElkIH0gZnJvbSAnLi4vLi4vZGlmZi90eXBlcyc7XG5pbXBvcnQgeyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yLCBNb250aGx5Q29zdCwgUHJpY2luZ0NsaWVudCB9IGZyb20gJy4uL3R5cGVzJztcbmltcG9ydCB7IG5vcm1hbGl6ZVJlZ2lvbiB9IGZyb20gJy4uL1JlZ2lvbk1hcHBlcic7XG5cbmV4cG9ydCBjbGFzcyBLaW5lc2lzQ2FsY3VsYXRvciBpbXBsZW1lbnRzIFJlc291cmNlQ29zdENhbGN1bGF0b3Ige1xuICBwcml2YXRlIHJlYWRvbmx5IEhPVVJTX1BFUl9NT05USCA9IDczMDtcblxuICAvLyBEYXRhIFN0cmVhbXMgLSBQcm92aXNpb25lZFxuICBwcml2YXRlIHJlYWRvbmx5IERFRkFVTFRfU0hBUkRfQ09VTlQgPSAyO1xuICBwcml2YXRlIHJlYWRvbmx5IEZBTExCQUNLX1NIQVJEX1BSSUNFID0gMC4wMTU7XG5cbiAgLy8gRGF0YSBTdHJlYW1zIC0gT24tRGVtYW5kXG4gIHByaXZhdGUgcmVhZG9ubHkgREVGQVVMVF9JTkdFU1RJT05fR0IgPSAxMDAwO1xuICBwcml2YXRlIHJlYWRvbmx5IERFRkFVTFRfUkVUUklFVkFMX0dCID0gMjAwMDtcbiAgcHJpdmF0ZSByZWFkb25seSBGQUxMQkFDS19JTkdFU1RJT05fUFJJQ0UgPSAwLjA0MDtcbiAgcHJpdmF0ZSByZWFkb25seSBGQUxMQkFDS19SRVRSSUVWQUxfUFJJQ0UgPSAwLjAxNTtcblxuICAvLyBGaXJlaG9zZVxuICBwcml2YXRlIHJlYWRvbmx5IERFRkFVTFRfRklSRUhPU0VfR0IgPSAxMDAwO1xuICBwcml2YXRlIHJlYWRvbmx5IEZBTExCQUNLX0ZJUkVIT1NFX1BSSUNFID0gMC4wMjk7XG5cbiAgLy8gQW5hbHl0aWNzXG4gIHByaXZhdGUgcmVhZG9ubHkgREVGQVVMVF9LUFVTID0gMjtcbiAgcHJpdmF0ZSByZWFkb25seSBGQUxMQkFDS19LUFVfUFJJQ0UgPSAwLjExO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgY3VzdG9tU2hhcmRDb3VudD86IG51bWJlcixcbiAgICBwcml2YXRlIHJlYWRvbmx5IGN1c3RvbUluZ2VzdGlvbkdCPzogbnVtYmVyLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgY3VzdG9tUmV0cmlldmFsR0I/OiBudW1iZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSBjdXN0b21GaXJlaG9zZUdCPzogbnVtYmVyLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgY3VzdG9tS1BVcz86IG51bWJlcixcbiAgKSB7fVxuXG4gIHN1cHBvcnRzKHJlc291cmNlVHlwZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIChcbiAgICAgIHJlc291cmNlVHlwZSA9PT0gJ0FXUzo6S2luZXNpczo6U3RyZWFtJyB8fFxuICAgICAgcmVzb3VyY2VUeXBlID09PSAnQVdTOjpLaW5lc2lzRmlyZWhvc2U6OkRlbGl2ZXJ5U3RyZWFtJyB8fFxuICAgICAgcmVzb3VyY2VUeXBlID09PSAnQVdTOjpLaW5lc2lzQW5hbHl0aWNzVjI6OkFwcGxpY2F0aW9uJ1xuICAgICk7XG4gIH1cblxuICBhc3luYyBjYWxjdWxhdGVDb3N0KFxuICAgIHJlc291cmNlOiBSZXNvdXJjZVdpdGhJZCxcbiAgICByZWdpb246IHN0cmluZyxcbiAgICBwcmljaW5nQ2xpZW50OiBQcmljaW5nQ2xpZW50LFxuICApOiBQcm9taXNlPE1vbnRobHlDb3N0PiB7XG4gICAgdHJ5IHtcbiAgICAgIHN3aXRjaCAocmVzb3VyY2UudHlwZSkge1xuICAgICAgICBjYXNlICdBV1M6OktpbmVzaXM6OlN0cmVhbSc6XG4gICAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuY2FsY3VsYXRlRGF0YVN0cmVhbUNvc3QocmVzb3VyY2UsIHJlZ2lvbiwgcHJpY2luZ0NsaWVudCk7XG4gICAgICAgIGNhc2UgJ0FXUzo6S2luZXNpc0ZpcmVob3NlOjpEZWxpdmVyeVN0cmVhbSc6XG4gICAgICAgICAgcmV0dXJuIHRoaXMuY2FsY3VsYXRlRmlyZWhvc2VDb3N0KCk7XG4gICAgICAgIGNhc2UgJ0FXUzo6S2luZXNpc0FuYWx5dGljc1YyOjpBcHBsaWNhdGlvbic6XG4gICAgICAgICAgcmV0dXJuIHRoaXMuY2FsY3VsYXRlQW5hbHl0aWNzQ29zdCgpO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgICAgICBjb25maWRlbmNlOiAndW5rbm93bicsXG4gICAgICAgICAgICBhc3N1bXB0aW9uczogW2BVbnN1cHBvcnRlZCBLaW5lc2lzIHJlc291cmNlIHR5cGU6ICR7cmVzb3VyY2UudHlwZX1gXSxcbiAgICAgICAgICB9O1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgICAgY29uZmlkZW5jZTogJ3Vua25vd24nLFxuICAgICAgICBhc3N1bXB0aW9uczogW2BGYWlsZWQgdG8gZmV0Y2ggcHJpY2luZzogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YF0sXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgY2FsY3VsYXRlRGF0YVN0cmVhbUNvc3QoXG4gICAgcmVzb3VyY2U6IFJlc291cmNlV2l0aElkLFxuICAgIHJlZ2lvbjogc3RyaW5nLFxuICAgIHByaWNpbmdDbGllbnQ6IFByaWNpbmdDbGllbnQsXG4gICk6IFByb21pc2U8TW9udGhseUNvc3Q+IHtcbiAgICBjb25zdCBwcm9wcyA9IHJlc291cmNlLnByb3BlcnRpZXMgfHwge307XG4gICAgY29uc3Qgc3RyZWFtTW9kZURldGFpbHMgPSBwcm9wcy5TdHJlYW1Nb2RlRGV0YWlscyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZDtcbiAgICBjb25zdCBzdHJlYW1Nb2RlID0gKHN0cmVhbU1vZGVEZXRhaWxzPy5TdHJlYW1Nb2RlIGFzIHN0cmluZykgfHwgJ1BST1ZJU0lPTkVEJztcblxuICAgIGlmIChzdHJlYW1Nb2RlID09PSAnT05fREVNQU5EJykge1xuICAgICAgcmV0dXJuIHRoaXMuY2FsY3VsYXRlT25EZW1hbmRTdHJlYW1Db3N0KCk7XG4gICAgfVxuXG4gICAgY29uc3Qgc2hhcmRDb3VudCA9IHRoaXMuY3VzdG9tU2hhcmRDb3VudFxuICAgICAgPz8gKHByb3BzLlNoYXJkQ291bnQgYXMgbnVtYmVyIHwgdW5kZWZpbmVkKVxuICAgICAgPz8gdGhpcy5ERUZBVUxUX1NIQVJEX0NPVU5UO1xuXG4gICAgY29uc3Qgc2hhcmRQcmljZSA9IGF3YWl0IHByaWNpbmdDbGllbnQuZ2V0UHJpY2Uoe1xuICAgICAgc2VydmljZUNvZGU6ICdBbWF6b25LaW5lc2lzJyxcbiAgICAgIHJlZ2lvbjogbm9ybWFsaXplUmVnaW9uKHJlZ2lvbiksXG4gICAgICBmaWx0ZXJzOiBbXG4gICAgICAgIHsgZmllbGQ6ICdwcm9kdWN0RmFtaWx5JywgdmFsdWU6ICdLaW5lc2lzIFN0cmVhbXMnIH0sXG4gICAgICAgIHsgZmllbGQ6ICd1c2FnZXR5cGUnLCB2YWx1ZTogJ3NoYXJkSG91ci1Qcm92aXNpb25lZCcgfSxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICBjb25zdCByYXRlID0gc2hhcmRQcmljZSA/PyB0aGlzLkZBTExCQUNLX1NIQVJEX1BSSUNFO1xuICAgIGNvbnN0IG1vbnRobHlDb3N0ID0gc2hhcmRDb3VudCAqIHJhdGUgKiB0aGlzLkhPVVJTX1BFUl9NT05USDtcblxuICAgIHJldHVybiB7XG4gICAgICBhbW91bnQ6IG1vbnRobHlDb3N0LFxuICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgY29uZmlkZW5jZTogc2hhcmRQcmljZSAhPT0gbnVsbCA/ICdoaWdoJyA6ICdtZWRpdW0nLFxuICAgICAgYXNzdW1wdGlvbnM6IFtcbiAgICAgICAgYFByb3Zpc2lvbmVkIG1vZGU6ICR7c2hhcmRDb3VudH0gc2hhcmRzIMOXICQke3JhdGUudG9GaXhlZCg0KX0vc2hhcmQtaG91ciDDlyAke3RoaXMuSE9VUlNfUEVSX01PTlRIfWggPSAkJHttb250aGx5Q29zdC50b0ZpeGVkKDIpfS9tb250aGAsXG4gICAgICAgIC4uLihzaGFyZFByaWNlID09PSBudWxsID8gW2BVc2luZyBmYWxsYmFjayBwcmljaW5nIChBUEkgZGF0YSBub3QgYXZhaWxhYmxlIGZvciByZWdpb24gJHtyZWdpb259KWBdIDogW10pLFxuICAgICAgXSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBjYWxjdWxhdGVPbkRlbWFuZFN0cmVhbUNvc3QoKTogTW9udGhseUNvc3Qge1xuICAgIGNvbnN0IGluZ2VzdGlvbkdCID0gdGhpcy5jdXN0b21Jbmdlc3Rpb25HQiA/PyB0aGlzLkRFRkFVTFRfSU5HRVNUSU9OX0dCO1xuICAgIGNvbnN0IHJldHJpZXZhbEdCID0gdGhpcy5jdXN0b21SZXRyaWV2YWxHQiA/PyB0aGlzLkRFRkFVTFRfUkVUUklFVkFMX0dCO1xuXG4gICAgY29uc3QgaW5nZXN0aW9uQ29zdCA9IGluZ2VzdGlvbkdCICogdGhpcy5GQUxMQkFDS19JTkdFU1RJT05fUFJJQ0U7XG4gICAgY29uc3QgcmV0cmlldmFsQ29zdCA9IHJldHJpZXZhbEdCICogdGhpcy5GQUxMQkFDS19SRVRSSUVWQUxfUFJJQ0U7XG4gICAgY29uc3QgdG90YWxDb3N0ID0gaW5nZXN0aW9uQ29zdCArIHJldHJpZXZhbENvc3Q7XG5cbiAgICByZXR1cm4ge1xuICAgICAgYW1vdW50OiB0b3RhbENvc3QsXG4gICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICBjb25maWRlbmNlOiAnbWVkaXVtJyxcbiAgICAgIGFzc3VtcHRpb25zOiBbXG4gICAgICAgIGBPbi1kZW1hbmQgbW9kZWAsXG4gICAgICAgIGBJbmdlc3Rpb246ICR7aW5nZXN0aW9uR0J9IEdCIMOXICQke3RoaXMuRkFMTEJBQ0tfSU5HRVNUSU9OX1BSSUNFfS9HQiA9ICQke2luZ2VzdGlvbkNvc3QudG9GaXhlZCgyKX0vbW9udGhgLFxuICAgICAgICBgUmV0cmlldmFsOiAke3JldHJpZXZhbEdCfSBHQiDDlyAkJHt0aGlzLkZBTExCQUNLX1JFVFJJRVZBTF9QUklDRX0vR0IgPSAkJHtyZXRyaWV2YWxDb3N0LnRvRml4ZWQoMil9L21vbnRoYCxcbiAgICAgIF0sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgY2FsY3VsYXRlRmlyZWhvc2VDb3N0KCk6IE1vbnRobHlDb3N0IHtcbiAgICBjb25zdCBkYXRhR0IgPSB0aGlzLmN1c3RvbUZpcmVob3NlR0IgPz8gdGhpcy5ERUZBVUxUX0ZJUkVIT1NFX0dCO1xuICAgIGNvbnN0IG1vbnRobHlDb3N0ID0gZGF0YUdCICogdGhpcy5GQUxMQkFDS19GSVJFSE9TRV9QUklDRTtcblxuICAgIHJldHVybiB7XG4gICAgICBhbW91bnQ6IG1vbnRobHlDb3N0LFxuICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgY29uZmlkZW5jZTogJ21lZGl1bScsXG4gICAgICBhc3N1bXB0aW9uczogW1xuICAgICAgICBgRmlyZWhvc2UgaW5nZXN0aW9uOiAke2RhdGFHQn0gR0Igw5cgJCR7dGhpcy5GQUxMQkFDS19GSVJFSE9TRV9QUklDRX0vR0IgPSAkJHttb250aGx5Q29zdC50b0ZpeGVkKDIpfS9tb250aGAsXG4gICAgICAgICdEb2VzIG5vdCBpbmNsdWRlIGZvcm1hdCBjb252ZXJzaW9uIG9yIFZQQyBkZWxpdmVyeSBjb3N0cycsXG4gICAgICBdLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGNhbGN1bGF0ZUFuYWx5dGljc0Nvc3QoKTogTW9udGhseUNvc3Qge1xuICAgIGNvbnN0IGtwdXMgPSB0aGlzLmN1c3RvbUtQVXMgPz8gdGhpcy5ERUZBVUxUX0tQVVM7XG4gICAgY29uc3QgbW9udGhseUNvc3QgPSBrcHVzICogdGhpcy5GQUxMQkFDS19LUFVfUFJJQ0UgKiB0aGlzLkhPVVJTX1BFUl9NT05USDtcblxuICAgIHJldHVybiB7XG4gICAgICBhbW91bnQ6IG1vbnRobHlDb3N0LFxuICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgY29uZmlkZW5jZTogJ21lZGl1bScsXG4gICAgICBhc3N1bXB0aW9uczogW1xuICAgICAgICBgS2luZXNpcyBBbmFseXRpY3M6ICR7a3B1c30gS1BVcyDDlyAkJHt0aGlzLkZBTExCQUNLX0tQVV9QUklDRX0vS1BVLWhvdXIgw5cgJHt0aGlzLkhPVVJTX1BFUl9NT05USH1oID0gJCR7bW9udGhseUNvc3QudG9GaXhlZCgyKX0vbW9udGhgLFxuICAgICAgICAnMSBLUFUgPSAxIHZDUFUgKyA0IEdCIG1lbW9yeScsXG4gICAgICBdLFxuICAgIH07XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,18 @@
1
+ import { ResourceWithId } from '../../diff/types';
2
+ import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
3
+ export declare class Route53Calculator implements ResourceCostCalculator {
4
+ private readonly customMonthlyQueries?;
5
+ private readonly HOSTED_ZONE_PRICE;
6
+ private readonly BASIC_HEALTH_CHECK_PRICE;
7
+ private readonly HTTPS_HEALTH_CHECK_PRICE;
8
+ private readonly STANDARD_QUERY_PRICE_PER_MILLION;
9
+ private readonly LATENCY_QUERY_PRICE_PER_MILLION;
10
+ private readonly GEO_QUERY_PRICE_PER_MILLION;
11
+ private readonly DEFAULT_MONTHLY_QUERIES;
12
+ constructor(customMonthlyQueries?: number | undefined);
13
+ supports(resourceType: string): boolean;
14
+ calculateCost(resource: ResourceWithId, _region: string, _pricingClient: PricingClient): Promise<MonthlyCost>;
15
+ private calculateHostedZoneCost;
16
+ private calculateHealthCheckCost;
17
+ private calculateRecordSetCost;
18
+ }
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Route53Calculator = void 0;
4
+ class Route53Calculator {
5
+ customMonthlyQueries;
6
+ HOSTED_ZONE_PRICE = 0.50;
7
+ BASIC_HEALTH_CHECK_PRICE = 0.50;
8
+ HTTPS_HEALTH_CHECK_PRICE = 1.00;
9
+ STANDARD_QUERY_PRICE_PER_MILLION = 0.40;
10
+ LATENCY_QUERY_PRICE_PER_MILLION = 0.60;
11
+ GEO_QUERY_PRICE_PER_MILLION = 0.70;
12
+ DEFAULT_MONTHLY_QUERIES = 1_000_000;
13
+ constructor(customMonthlyQueries) {
14
+ this.customMonthlyQueries = customMonthlyQueries;
15
+ }
16
+ supports(resourceType) {
17
+ return (resourceType === 'AWS::Route53::HostedZone' ||
18
+ resourceType === 'AWS::Route53::HealthCheck' ||
19
+ resourceType === 'AWS::Route53::RecordSet');
20
+ }
21
+ async calculateCost(resource, _region, _pricingClient) {
22
+ switch (resource.type) {
23
+ case 'AWS::Route53::HostedZone':
24
+ return this.calculateHostedZoneCost();
25
+ case 'AWS::Route53::HealthCheck':
26
+ return this.calculateHealthCheckCost(resource);
27
+ case 'AWS::Route53::RecordSet':
28
+ return this.calculateRecordSetCost(resource);
29
+ default:
30
+ return {
31
+ amount: 0,
32
+ currency: 'USD',
33
+ confidence: 'unknown',
34
+ assumptions: [`Unsupported Route 53 resource type: ${resource.type}`],
35
+ };
36
+ }
37
+ }
38
+ calculateHostedZoneCost() {
39
+ return {
40
+ amount: this.HOSTED_ZONE_PRICE,
41
+ currency: 'USD',
42
+ confidence: 'high',
43
+ assumptions: [
44
+ `Hosted zone: $${this.HOSTED_ZONE_PRICE.toFixed(2)}/month`,
45
+ 'DNS query costs are calculated on RecordSet resources',
46
+ ],
47
+ };
48
+ }
49
+ calculateHealthCheckCost(resource) {
50
+ const props = resource.properties || {};
51
+ const healthCheckConfig = props.HealthCheckConfig;
52
+ const checkType = healthCheckConfig?.Type || 'HTTP';
53
+ const isAdvanced = ['HTTPS', 'HTTP_STR_MATCH', 'HTTPS_STR_MATCH'].includes(checkType);
54
+ const price = isAdvanced ? this.HTTPS_HEALTH_CHECK_PRICE : this.BASIC_HEALTH_CHECK_PRICE;
55
+ return {
56
+ amount: price,
57
+ currency: 'USD',
58
+ confidence: 'high',
59
+ assumptions: [
60
+ `Health check (${checkType}): $${price.toFixed(2)}/month`,
61
+ ],
62
+ };
63
+ }
64
+ calculateRecordSetCost(resource) {
65
+ const props = resource.properties || {};
66
+ // Alias records to AWS resources are free
67
+ if (props.AliasTarget) {
68
+ return {
69
+ amount: 0,
70
+ currency: 'USD',
71
+ confidence: 'high',
72
+ assumptions: ['Alias record to AWS resource: no query charges'],
73
+ };
74
+ }
75
+ const queries = this.customMonthlyQueries ?? this.DEFAULT_MONTHLY_QUERIES;
76
+ const queriesInMillions = queries / 1_000_000;
77
+ let pricePerMillion = this.STANDARD_QUERY_PRICE_PER_MILLION;
78
+ let routingType = 'standard';
79
+ if (props.Region) {
80
+ pricePerMillion = this.LATENCY_QUERY_PRICE_PER_MILLION;
81
+ routingType = 'latency-based';
82
+ }
83
+ else if (props.GeoLocation) {
84
+ pricePerMillion = this.GEO_QUERY_PRICE_PER_MILLION;
85
+ routingType = 'geolocation';
86
+ }
87
+ const monthlyCost = queriesInMillions * pricePerMillion;
88
+ return {
89
+ amount: monthlyCost,
90
+ currency: 'USD',
91
+ confidence: 'medium',
92
+ assumptions: [
93
+ `DNS queries (${routingType}): ${queriesInMillions}M × $${pricePerMillion.toFixed(2)}/M = $${monthlyCost.toFixed(2)}/month`,
94
+ ],
95
+ };
96
+ }
97
+ }
98
+ exports.Route53Calculator = Route53Calculator;
99
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUm91dGU1M0NhbGN1bGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcHJpY2luZy9jYWxjdWxhdG9ycy9Sb3V0ZTUzQ2FsY3VsYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFHQSxNQUFhLGlCQUFpQjtJQVVUO0lBVEYsaUJBQWlCLEdBQUcsSUFBSSxDQUFDO0lBQ3pCLHdCQUF3QixHQUFHLElBQUksQ0FBQztJQUNoQyx3QkFBd0IsR0FBRyxJQUFJLENBQUM7SUFDaEMsZ0NBQWdDLEdBQUcsSUFBSSxDQUFDO0lBQ3hDLCtCQUErQixHQUFHLElBQUksQ0FBQztJQUN2QywyQkFBMkIsR0FBRyxJQUFJLENBQUM7SUFDbkMsdUJBQXVCLEdBQUcsU0FBUyxDQUFDO0lBRXJELFlBQ21CLG9CQUE2QjtRQUE3Qix5QkFBb0IsR0FBcEIsb0JBQW9CLENBQVM7SUFDN0MsQ0FBQztJQUVKLFFBQVEsQ0FBQyxZQUFvQjtRQUMzQixPQUFPLENBQ0wsWUFBWSxLQUFLLDBCQUEwQjtZQUMzQyxZQUFZLEtBQUssMkJBQTJCO1lBQzVDLFlBQVksS0FBSyx5QkFBeUIsQ0FDM0MsQ0FBQztJQUNKLENBQUM7SUFFRCxLQUFLLENBQUMsYUFBYSxDQUNqQixRQUF3QixFQUN4QixPQUFlLEVBQ2YsY0FBNkI7UUFFN0IsUUFBUSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDdEIsS0FBSywwQkFBMEI7Z0JBQzdCLE9BQU8sSUFBSSxDQUFDLHVCQUF1QixFQUFFLENBQUM7WUFDeEMsS0FBSywyQkFBMkI7Z0JBQzlCLE9BQU8sSUFBSSxDQUFDLHdCQUF3QixDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ2pELEtBQUsseUJBQXlCO2dCQUM1QixPQUFPLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUMvQztnQkFDRSxPQUFPO29CQUNMLE1BQU0sRUFBRSxDQUFDO29CQUNULFFBQVEsRUFBRSxLQUFLO29CQUNmLFVB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IFJlc291cmNlV2l0aElkIH0gZnJvbSAnLi4vLi4vZGlmZi90eXBlcyc7XG5pbXBvcnQgeyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yLCBNb250aGx5Q29zdCwgUHJpY2luZ0NsaWVudCB9IGZyb20gJy4uL3R5cGVzJztcblxuZXhwb3J0IGNsYXNzIFJvdXRlNTNDYWxjdWxhdG9yIGltcGxlbWVudHMgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciB7XG4gIHByaXZhdGUgcmVhZG9ubHkgSE9TVEVEX1pPTkVfUFJJQ0UgPSAwLjUwO1xuICBwcml2YXRlIHJlYWRvbmx5IEJBU0lDX0hFQUxUSF9DSEVDS19QUklDRSA9IDAuNTA7XG4gIHByaXZhdGUgcmVhZG9ubHkgSFRUUFNfSEVBTFRIX0NIRUNLX1BSSUNFID0gMS4wMDtcbiAgcHJpdmF0ZSByZWFkb25seSBTVEFOREFSRF9RVUVSWV9QUklDRV9QRVJfTUlMTElPTiA9IDAuNDA7XG4gIHByaXZhdGUgcmVhZG9ubHkgTEFURU5DWV9RVUVSWV9QUklDRV9QRVJfTUlMTElPTiA9IDAuNjA7XG4gIHByaXZhdGUgcmVhZG9ubHkgR0VPX1FVRVJZX1BSSUNFX1BFUl9NSUxMSU9OID0gMC43MDtcbiAgcHJpdmF0ZSByZWFkb25seSBERUZBVUxUX01PTlRITFlfUVVFUklFUyA9IDFfMDAwXzAwMDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IGN1c3RvbU1vbnRobHlRdWVyaWVzPzogbnVtYmVyLFxuICApIHt9XG5cbiAgc3VwcG9ydHMocmVzb3VyY2VUeXBlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gKFxuICAgICAgcmVzb3VyY2VUeXBlID09PSAnQVdTOjpSb3V0ZTUzOjpIb3N0ZWRab25lJyB8fFxuICAgICAgcmVzb3VyY2VUeXBlID09PSAnQVdTOjpSb3V0ZTUzOjpIZWFsdGhDaGVjaycgfHxcbiAgICAgIHJlc291cmNlVHlwZSA9PT0gJ0FXUzo6Um91dGU1Mzo6UmVjb3JkU2V0J1xuICAgICk7XG4gIH1cblxuICBhc3luYyBjYWxjdWxhdGVDb3N0KFxuICAgIHJlc291cmNlOiBSZXNvdXJjZVdpdGhJZCxcbiAgICBfcmVnaW9uOiBzdHJpbmcsXG4gICAgX3ByaWNpbmdDbGllbnQ6IFByaWNpbmdDbGllbnQsXG4gICk6IFByb21pc2U8TW9udGhseUNvc3Q+IHtcbiAgICBzd2l0Y2ggKHJlc291cmNlLnR5cGUpIHtcbiAgICAgIGNhc2UgJ0FXUzo6Um91dGU1Mzo6SG9zdGVkWm9uZSc6XG4gICAgICAgIHJldHVybiB0aGlzLmNhbGN1bGF0ZUhvc3RlZFpvbmVDb3N0KCk7XG4gICAgICBjYXNlICdBV1M6OlJvdXRlNTM6OkhlYWx0aENoZWNrJzpcbiAgICAgICAgcmV0dXJuIHRoaXMuY2FsY3VsYXRlSGVhbHRoQ2hlY2tDb3N0KHJlc291cmNlKTtcbiAgICAgIGNhc2UgJ0FXUzo6Um91dGU1Mzo6UmVjb3JkU2V0JzpcbiAgICAgICAgcmV0dXJuIHRoaXMuY2FsY3VsYXRlUmVjb3JkU2V0Q29zdChyZXNvdXJjZSk7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgICAgY29uZmlkZW5jZTogJ3Vua25vd24nLFxuICAgICAgICAgIGFzc3VtcHRpb25zOiBbYFVuc3VwcG9ydGVkIFJvdXRlIDUzIHJlc291cmNlIHR5cGU6ICR7cmVzb3VyY2UudHlwZX1gXSxcbiAgICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGNhbGN1bGF0ZUhvc3RlZFpvbmVDb3N0KCk6IE1vbnRobHlDb3N0IHtcbiAgICByZXR1cm4ge1xuICAgICAgYW1vdW50OiB0aGlzLkhPU1RFRF9aT05FX1BSSUNFLFxuICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgY29uZmlkZW5jZTogJ2hpZ2gnLFxuICAgICAgYXNzdW1wdGlvbnM6IFtcbiAgICAgICAgYEhvc3RlZCB6b25lOiAkJHt0aGlzLkhPU1RFRF9aT05FX1BSSUNFLnRvRml4ZWQoMil9L21vbnRoYCxcbiAgICAgICAgJ0ROUyBxdWVyeSBjb3N0cyBhcmUgY2FsY3VsYXRlZCBvbiBSZWNvcmRTZXQgcmVzb3VyY2VzJyxcbiAgICAgIF0sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgY2FsY3VsYXRlSGVhbHRoQ2hlY2tDb3N0KHJlc291cmNlOiBSZXNvdXJjZVdpdGhJZCk6IE1vbnRobHlDb3N0IHtcbiAgICBjb25zdCBwcm9wcyA9IHJlc291cmNlLnByb3BlcnRpZXMgfHwge307XG4gICAgY29uc3QgaGVhbHRoQ2hlY2tDb25maWcgPSBwcm9wcy5IZWFsdGhDaGVja0NvbmZpZyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZDtcbiAgICBjb25zdCBjaGVja1R5cGUgPSAoaGVhbHRoQ2hlY2tDb25maWc/LlR5cGUgYXMgc3RyaW5nKSB8fCAnSFRUUCc7XG5cbiAgICBjb25zdCBpc0FkdmFuY2VkID0gWydIVFRQUycsICdIVFRQX1NUUl9NQVRDSCcsICdIVFRQU19TVFJfTUFUQ0gnXS5pbmNsdWRlcyhjaGVja1R5cGUpO1xuICAgIGNvbnN0IHByaWNlID0gaXNBZHZhbmNlZCA/IHRoaXMuSFRUUFNfSEVBTFRIX0NIRUNLX1BSSUNFIDogdGhpcy5CQVNJQ19IRUFMVEhfQ0hFQ0tfUFJJQ0U7XG5cbiAgICByZXR1cm4ge1xuICAgICAgYW1vdW50OiBwcmljZSxcbiAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgIGNvbmZpZGVuY2U6ICdoaWdoJyxcbiAgICAgIGFzc3VtcHRpb25zOiBbXG4gICAgICAgIGBIZWFsdGggY2hlY2sgKCR7Y2hlY2tUeXBlfSk6ICQke3ByaWNlLnRvRml4ZWQoMil9L21vbnRoYCxcbiAgICAgIF0sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgY2FsY3VsYXRlUmVjb3JkU2V0Q29zdChyZXNvdXJjZTogUmVzb3VyY2VXaXRoSWQpOiBNb250aGx5Q29zdCB7XG4gICAgY29uc3QgcHJvcHMgPSByZXNvdXJjZS5wcm9wZXJ0aWVzIHx8IHt9O1xuXG4gICAgLy8gQWxpYXMgcmVjb3JkcyB0byBBV1MgcmVzb3VyY2VzIGFyZSBmcmVlXG4gICAgaWYgKHByb3BzLkFsaWFzVGFyZ2V0KSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgICAgY29uZmlkZW5jZTogJ2hpZ2gnLFxuICAgICAgICBhc3N1bXB0aW9uczogWydBbGlhcyByZWNvcmQgdG8gQVdTIHJlc291cmNlOiBubyBxdWVyeSBjaGFyZ2VzJ10sXG4gICAgICB9O1xuICAgIH1cblxuICAgIGNvbnN0IHF1ZXJpZXMgPSB0aGlzLmN1c3RvbU1vbnRobHlRdWVyaWVzID8/IHRoaXMuREVGQVVMVF9NT05USExZX1FVRVJJRVM7XG4gICAgY29uc3QgcXVlcmllc0luTWlsbGlvbnMgPSBxdWVyaWVzIC8gMV8wMDBfMDAwO1xuXG4gICAgbGV0IHByaWNlUGVyTWlsbGlvbiA9IHRoaXMuU1RBTkRBUkRfUVVFUllfUFJJQ0VfUEVSX01JTExJT047XG4gICAgbGV0IHJvdXRpbmdUeXBlID0gJ3N0YW5kYXJkJztcblxuICAgIGlmIChwcm9wcy5SZWdpb24pIHtcbiAgICAgIHByaWNlUGVyTWlsbGlvbiA9IHRoaXMuTEFURU5DWV9RVUVSWV9QUklDRV9QRVJfTUlMTElPTjtcbiAgICAgIHJvdXRpbmdUeXBlID0gJ2xhdGVuY3ktYmFzZWQnO1xuICAgIH0gZWxzZSBpZiAocHJvcHMuR2VvTG9jYXRpb24pIHtcbiAgICAgIHByaWNlUGVyTWlsbGlvbiA9IHRoaXMuR0VPX1FVRVJZX1BSSUNFX1BFUl9NSUxMSU9OO1xuICAgICAgcm91dGluZ1R5cGUgPSAnZ2VvbG9jYXRpb24nO1xuICAgIH1cblxuICAgIGNvbnN0IG1vbnRobHlDb3N0ID0gcXVlcmllc0luTWlsbGlvbnMgKiBwcmljZVBlck1pbGxpb247XG5cbiAgICByZXR1cm4ge1xuICAgICAgYW1vdW50OiBtb250aGx5Q29zdCxcbiAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgIGNvbmZpZGVuY2U6ICdtZWRpdW0nLFxuICAgICAgYXNzdW1wdGlvbnM6IFtcbiAgICAgICAgYEROUyBxdWVyaWVzICgke3JvdXRpbmdUeXBlfSk6ICR7cXVlcmllc0luTWlsbGlvbnN9TSDDlyAkJHtwcmljZVBlck1pbGxpb24udG9GaXhlZCgyKX0vTSA9ICQke21vbnRobHlDb3N0LnRvRml4ZWQoMil9L21vbnRoYCxcbiAgICAgIF0sXG4gICAgfTtcbiAgfVxufVxuIl19
@@ -0,0 +1,16 @@
1
+ import { ResourceWithId } from '../../diff/types';
2
+ import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
3
+ export declare class TransitGatewayCalculator implements ResourceCostCalculator {
4
+ private readonly customAttachments?;
5
+ private readonly customMonthlyDataGB?;
6
+ private readonly HOURS_PER_MONTH;
7
+ private readonly DEFAULT_ATTACHMENTS;
8
+ private readonly DEFAULT_MONTHLY_DATA_GB;
9
+ private readonly FALLBACK_ATTACHMENT_PRICE;
10
+ private readonly FALLBACK_DATA_PRICE;
11
+ constructor(customAttachments?: number | undefined, customMonthlyDataGB?: number | undefined);
12
+ supports(resourceType: string): boolean;
13
+ calculateCost(resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
14
+ private calculateAttachmentCost;
15
+ private calculateTransitGatewayCost;
16
+ }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TransitGatewayCalculator = void 0;
4
+ const RegionMapper_1 = require("../RegionMapper");
5
+ class TransitGatewayCalculator {
6
+ customAttachments;
7
+ customMonthlyDataGB;
8
+ HOURS_PER_MONTH = 730;
9
+ DEFAULT_ATTACHMENTS = 3;
10
+ DEFAULT_MONTHLY_DATA_GB = 1000;
11
+ FALLBACK_ATTACHMENT_PRICE = 0.05;
12
+ FALLBACK_DATA_PRICE = 0.02;
13
+ constructor(customAttachments, customMonthlyDataGB) {
14
+ this.customAttachments = customAttachments;
15
+ this.customMonthlyDataGB = customMonthlyDataGB;
16
+ }
17
+ supports(resourceType) {
18
+ return (resourceType === 'AWS::EC2::TransitGateway' ||
19
+ resourceType === 'AWS::EC2::TransitGatewayAttachment');
20
+ }
21
+ async calculateCost(resource, region, pricingClient) {
22
+ try {
23
+ if (resource.type === 'AWS::EC2::TransitGatewayAttachment') {
24
+ return await this.calculateAttachmentCost(region, pricingClient);
25
+ }
26
+ return await this.calculateTransitGatewayCost(region, pricingClient);
27
+ }
28
+ catch (error) {
29
+ return {
30
+ amount: 0,
31
+ currency: 'USD',
32
+ confidence: 'unknown',
33
+ assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
34
+ };
35
+ }
36
+ }
37
+ async calculateAttachmentCost(region, pricingClient) {
38
+ const hourlyRate = await pricingClient.getPrice({
39
+ serviceCode: 'AmazonVPC',
40
+ region: (0, RegionMapper_1.normalizeRegion)(region),
41
+ filters: [
42
+ { field: 'productFamily', value: 'TransitGateway' },
43
+ { field: 'operation', value: 'TransitGatewayVPCAttachment' },
44
+ ],
45
+ });
46
+ const rate = hourlyRate ?? this.FALLBACK_ATTACHMENT_PRICE;
47
+ const monthlyCost = rate * this.HOURS_PER_MONTH;
48
+ return {
49
+ amount: monthlyCost,
50
+ currency: 'USD',
51
+ confidence: hourlyRate !== null ? 'high' : 'medium',
52
+ assumptions: [
53
+ `Transit Gateway attachment: $${rate.toFixed(4)}/hour × ${this.HOURS_PER_MONTH}h = $${monthlyCost.toFixed(2)}/month`,
54
+ ...(hourlyRate === null ? [`Using fallback pricing (API data not available for region ${region})`] : []),
55
+ 'Data processing costs are calculated on the Transit Gateway resource',
56
+ ],
57
+ };
58
+ }
59
+ async calculateTransitGatewayCost(region, pricingClient) {
60
+ const hourlyRate = await pricingClient.getPrice({
61
+ serviceCode: 'AmazonVPC',
62
+ region: (0, RegionMapper_1.normalizeRegion)(region),
63
+ filters: [
64
+ { field: 'productFamily', value: 'TransitGateway' },
65
+ { field: 'operation', value: 'TransitGatewayVPCAttachment' },
66
+ ],
67
+ });
68
+ const dataRate = await pricingClient.getPrice({
69
+ serviceCode: 'AmazonVPC',
70
+ region: (0, RegionMapper_1.normalizeRegion)(region),
71
+ filters: [
72
+ { field: 'productFamily', value: 'TransitGateway' },
73
+ { field: 'operation', value: 'TransitGatewayData' },
74
+ ],
75
+ });
76
+ const attachmentRate = hourlyRate ?? this.FALLBACK_ATTACHMENT_PRICE;
77
+ const dataProcessingRate = dataRate ?? this.FALLBACK_DATA_PRICE;
78
+ const usedFallback = hourlyRate === null || dataRate === null;
79
+ const attachments = this.customAttachments ?? this.DEFAULT_ATTACHMENTS;
80
+ const monthlyDataGB = this.customMonthlyDataGB ?? this.DEFAULT_MONTHLY_DATA_GB;
81
+ const attachmentCost = attachments * attachmentRate * this.HOURS_PER_MONTH;
82
+ const dataProcessingCost = monthlyDataGB * dataProcessingRate;
83
+ const totalCost = attachmentCost + dataProcessingCost;
84
+ return {
85
+ amount: totalCost,
86
+ currency: 'USD',
87
+ confidence: 'medium',
88
+ assumptions: [
89
+ `${attachments} attachments × $${attachmentRate.toFixed(4)}/hour × ${this.HOURS_PER_MONTH}h = $${attachmentCost.toFixed(2)}/month`,
90
+ `Data processing: ${monthlyDataGB} GB × $${dataProcessingRate.toFixed(4)}/GB = $${dataProcessingCost.toFixed(2)}/month`,
91
+ ...(usedFallback ? [`Using fallback pricing (API data not available for region ${region})`] : []),
92
+ ],
93
+ };
94
+ }
95
+ }
96
+ exports.TransitGatewayCalculator = TransitGatewayCalculator;
97
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVHJhbnNpdEdhdGV3YXlDYWxjdWxhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ByaWNpbmcvY2FsY3VsYXRvcnMvVHJhbnNpdEdhdGV3YXlDYWxjdWxhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBLGtEQUFrRDtBQUVsRCxNQUFhLHdCQUF3QjtJQVFoQjtJQUNBO0lBUkYsZUFBZSxHQUFHLEdBQUcsQ0FBQztJQUN0QixtQkFBbUIsR0FBRyxDQUFDLENBQUM7SUFDeEIsdUJBQXVCLEdBQUcsSUFBSSxDQUFDO0lBQy9CLHlCQUF5QixHQUFHLElBQUksQ0FBQztJQUNqQyxtQkFBbUIsR0FBRyxJQUFJLENBQUM7SUFFNUMsWUFDbUIsaUJBQTBCLEVBQzFCLG1CQUE0QjtRQUQ1QixzQkFBaUIsR0FBakIsaUJBQWlCLENBQVM7UUFDMUIsd0JBQW1CLEdBQW5CLG1CQUFtQixDQUFTO0lBQzVDLENBQUM7SUFFSixRQUFRLENBQUMsWUFBb0I7UUFDM0IsT0FBTyxDQUNMLFlBQVksS0FBSywwQkFBMEI7WUFDM0MsWUFBWSxLQUFLLG9DQUFvQyxDQUN0RCxDQUFDO0lBQ0osQ0FBQztJQUVELEtBQUssQ0FBQyxhQUFhLENBQ2pCLFFBQXdCLEVBQ3hCLE1BQWMsRUFDZCxhQUE0QjtRQUU1QixJQUFJLENBQUM7WUFDSCxJQUFJLFFBQVEsQ0FBQyxJQUFJLEtBQUssb0NBQW9DLEVBQUUsQ0FBQztnQkFDM0QsT0FBTyxNQUFNLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxNQUFNLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFDbkUsQ0FBQztZQUNELE9BQU8sTUFBTSxJQUFJLENBQUMsMkJBQTJCLENBQUMsTUFBTSxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBQ3ZFLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsT0FBTztnQkFDTCxNQUFNLEVBQUUsQ0FBQztnQkFDVCxRQUFRLEVBQUUsS0FBSztnQkFDZixVQUFV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QUFjLEdBQUcsV0FBVyxHQUFHLGNBQWMsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDO1FBQzNFLE1BQU0sa0JBQWtCLEdBQUcsYUFBYSxHQUFHLGtCQUFrQixDQUFDO1FBQzlELE1BQU0sU0FBUyxHQUFHLGNBQWMsR0FBRyxrQkFBa0IsQ0FBQztRQUV0RCxPQUFPO1lBQ0wsTUFBTSxFQUFFLFNBQVM7WUFDakIsUUFBUSxFQUFFLEtBQUs7WUFDZixVQUFVLEVBQUUsUUFBUTtZQUNwQixXQUFXLEVBQUU7Z0JBQ1gsR0FBRyxXQUFXLG1CQUFtQixjQUFjLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxXQUFXLElBQUksQ0FBQyxlQUFlLFFBQVEsY0FBYyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsUUFBUTtnQkFDbEksb0JBQW9CLGFBQWEsVUFBVSxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFVBQVUsa0JBQWtCLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxRQUFRO2dCQUN2SCxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLDZEQUE2RCxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7YUFDbEc7U0FDRixDQUFDO0lBQ0osQ0FBQztDQUNGO0FBL0dELDREQStHQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJlc291cmNlV2l0aElkIH0gZnJvbSAnLi4vLi4vZGlmZi90eXBlcyc7XG5pbXBvcnQgeyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yLCBNb250aGx5Q29zdCwgUHJpY2luZ0NsaWVudCB9IGZyb20gJy4uL3R5cGVzJztcbmltcG9ydCB7IG5vcm1hbGl6ZVJlZ2lvbiB9IGZyb20gJy4uL1JlZ2lvbk1hcHBlcic7XG5cbmV4cG9ydCBjbGFzcyBUcmFuc2l0R2F0ZXdheUNhbGN1bGF0b3IgaW1wbGVtZW50cyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yIHtcbiAgcHJpdmF0ZSByZWFkb25seSBIT1VSU19QRVJfTU9OVEggPSA3MzA7XG4gIHByaXZhdGUgcmVhZG9ubHkgREVGQVVMVF9BVFRBQ0hNRU5UUyA9IDM7XG4gIHByaXZhdGUgcmVhZG9ubHkgREVGQVVMVF9NT05USExZX0RBVEFfR0IgPSAxMDAwO1xuICBwcml2YXRlIHJlYWRvbmx5IEZBTExCQUNLX0FUVEFDSE1FTlRfUFJJQ0UgPSAwLjA1O1xuICBwcml2YXRlIHJlYWRvbmx5IEZBTExCQUNLX0RBVEFfUFJJQ0UgPSAwLjAyO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgY3VzdG9tQXR0YWNobWVudHM/OiBudW1iZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSBjdXN0b21Nb250aGx5RGF0YUdCPzogbnVtYmVyLFxuICApIHt9XG5cbiAgc3VwcG9ydHMocmVzb3VyY2VUeXBlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gKFxuICAgICAgcmVzb3VyY2VUeXBlID09PSAnQVdTOjpFQzI6OlRyYW5zaXRHYXRld2F5JyB8fFxuICAgICAgcmVzb3VyY2VUeXBlID09PSAnQVdTOjpFQzI6OlRyYW5zaXRHYXRld2F5QXR0YWNobWVudCdcbiAgICApO1xuICB9XG5cbiAgYXN5bmMgY2FsY3VsYXRlQ29zdChcbiAgICByZXNvdXJjZTogUmVzb3VyY2VXaXRoSWQsXG4gICAgcmVnaW9uOiBzdHJpbmcsXG4gICAgcHJpY2luZ0NsaWVudDogUHJpY2luZ0NsaWVudCxcbiAgKTogUHJvbWlzZTxNb250aGx5Q29zdD4ge1xuICAgIHRyeSB7XG4gICAgICBpZiAocmVzb3VyY2UudHlwZSA9PT0gJ0FXUzo6RUMyOjpUcmFuc2l0R2F0ZXdheUF0dGFjaG1lbnQnKSB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmNhbGN1bGF0ZUF0dGFjaG1lbnRDb3N0KHJlZ2lvbiwgcHJpY2luZ0NsaWVudCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy5jYWxjdWxhdGVUcmFuc2l0R2F0ZXdheUNvc3QocmVnaW9uLCBwcmljaW5nQ2xpZW50KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtgRmFpbGVkIHRvIGZldGNoIHByaWNpbmc6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWBdLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGNhbGN1bGF0ZUF0dGFjaG1lbnRDb3N0KFxuICAgIHJlZ2lvbjogc3RyaW5nLFxuICAgIHByaWNpbmdDbGllbnQ6IFByaWNpbmdDbGllbnQsXG4gICk6IFByb21pc2U8TW9udGhseUNvc3Q+IHtcbiAgICBjb25zdCBob3VybHlSYXRlID0gYXdhaXQgcHJpY2luZ0NsaWVudC5nZXRQcmljZSh7XG4gICAgICBzZXJ2aWNlQ29kZTogJ0FtYXpvblZQQycsXG4gICAgICByZWdpb246IG5vcm1hbGl6ZVJlZ2lvbihyZWdpb24pLFxuICAgICAgZmlsdGVyczogW1xuICAgICAgICB7IGZpZWxkOiAncHJvZHVjdEZhbWlseScsIHZhbHVlOiAnVHJhbnNpdEdhdGV3YXknIH0sXG4gICAgICAgIHsgZmllbGQ6ICdvcGVyYXRpb24nLCB2YWx1ZTogJ1RyYW5zaXRHYXRld2F5VlBDQXR0YWNobWVudCcgfSxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICBjb25zdCByYXRlID0gaG91cmx5UmF0ZSA/PyB0aGlzLkZBTExCQUNLX0FUVEFDSE1FTlRfUFJJQ0U7XG4gICAgY29uc3QgbW9udGhseUNvc3QgPSByYXRlICogdGhpcy5IT1VSU19QRVJfTU9OVEg7XG5cbiAgICByZXR1cm4ge1xuICAgICAgYW1vdW50OiBtb250aGx5Q29zdCxcbiAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgIGNvbmZpZGVuY2U6IGhvdXJseVJhdGUgIT09IG51bGwgPyAnaGlnaCcgOiAnbWVkaXVtJyxcbiAgICAgIGFzc3VtcHRpb25zOiBbXG4gICAgICAgIGBUcmFuc2l0IEdhdGV3YXkgYXR0YWNobWVudDogJCR7cmF0ZS50b0ZpeGVkKDQpfS9ob3VyIMOXICR7dGhpcy5IT1VSU19QRVJfTU9OVEh9aCA9ICQke21vbnRobHlDb3N0LnRvRml4ZWQoMil9L21vbnRoYCxcbiAgICAgICAgLi4uKGhvdXJseVJhdGUgPT09IG51bGwgPyBbYFVzaW5nIGZhbGxiYWNrIHByaWNpbmcgKEFQSSBkYXRhIG5vdCBhdmFpbGFibGUgZm9yIHJlZ2lvbiAke3JlZ2lvbn0pYF0gOiBbXSksXG4gICAgICAgICdEYXRhIHByb2Nlc3NpbmcgY29zdHMgYXJlIGNhbGN1bGF0ZWQgb24gdGhlIFRyYW5zaXQgR2F0ZXdheSByZXNvdXJjZScsXG4gICAgICBdLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGNhbGN1bGF0ZVRyYW5zaXRHYXRld2F5Q29zdChcbiAgICByZWdpb246IHN0cmluZyxcbiAgICBwcmljaW5nQ2xpZW50OiBQcmljaW5nQ2xpZW50LFxuICApOiBQcm9taXNlPE1vbnRobHlDb3N0PiB7XG4gICAgY29uc3QgaG91cmx5UmF0ZSA9IGF3YWl0IHByaWNpbmdDbGllbnQuZ2V0UHJpY2Uoe1xuICAgICAgc2VydmljZUNvZGU6ICdBbWF6b25WUEMnLFxuICAgICAgcmVnaW9uOiBub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgIGZpbHRlcnM6IFtcbiAgICAgICAgeyBmaWVsZDogJ3Byb2R1Y3RGYW1pbHknLCB2YWx1ZTogJ1RyYW5zaXRHYXRld2F5JyB9LFxuICAgICAgICB7IGZpZWxkOiAnb3BlcmF0aW9uJywgdmFsdWU6ICdUcmFuc2l0R2F0ZXdheVZQQ0F0dGFjaG1lbnQnIH0sXG4gICAgICBdLFxuICAgIH0pO1xuXG4gICAgY29uc3QgZGF0YVJhdGUgPSBhd2FpdCBwcmljaW5nQ2xpZW50LmdldFByaWNlKHtcbiAgICAgIHNlcnZpY2VDb2RlOiAnQW1hem9uVlBDJyxcbiAgICAgIHJlZ2lvbjogbm9ybWFsaXplUmVnaW9uKHJlZ2lvbiksXG4gICAgICBmaWx0ZXJzOiBbXG4gICAgICAgIHsgZmllbGQ6ICdwcm9kdWN0RmFtaWx5JywgdmFsdWU6ICdUcmFuc2l0R2F0ZXdheScgfSxcbiAgICAgICAgeyBmaWVsZDogJ29wZXJhdGlvbicsIHZhbHVlOiAnVHJhbnNpdEdhdGV3YXlEYXRhJyB9LFxuICAgICAgXSxcbiAgICB9KTtcblxuICAgIGNvbnN0IGF0dGFjaG1lbnRSYXRlID0gaG91cmx5UmF0ZSA/PyB0aGlzLkZBTExCQUNLX0FUVEFDSE1FTlRfUFJJQ0U7XG4gICAgY29uc3QgZGF0YVByb2Nlc3NpbmdSYXRlID0gZGF0YVJhdGUgPz8gdGhpcy5GQUxMQkFDS19EQVRBX1BSSUNFO1xuICAgIGNvbnN0IHVzZWRGYWxsYmFjayA9IGhvdXJseVJhdGUgPT09IG51bGwgfHwgZGF0YVJhdGUgPT09IG51bGw7XG5cbiAgICBjb25zdCBhdHRhY2htZW50cyA9IHRoaXMuY3VzdG9tQXR0YWNobWVudHMgPz8gdGhpcy5ERUZBVUxUX0FUVEFDSE1FTlRTO1xuICAgIGNvbnN0IG1vbnRobHlEYXRhR0IgPSB0aGlzLmN1c3RvbU1vbnRobHlEYXRhR0IgPz8gdGhpcy5ERUZBVUxUX01PTlRITFlfREFUQV9HQjtcblxuICAgIGNvbnN0IGF0dGFjaG1lbnRDb3N0ID0gYXR0YWNobWVudHMgKiBhdHRhY2htZW50UmF0ZSAqIHRoaXMuSE9VUlNfUEVSX01PTlRIO1xuICAgIGNvbnN0IGRhdGFQcm9jZXNzaW5nQ29zdCA9IG1vbnRobHlEYXRhR0IgKiBkYXRhUHJvY2Vzc2luZ1JhdGU7XG4gICAgY29uc3QgdG90YWxDb3N0ID0gYXR0YWNobWVudENvc3QgKyBkYXRhUHJvY2Vzc2luZ0Nvc3Q7XG5cbiAgICByZXR1cm4ge1xuICAgICAgYW1vdW50OiB0b3RhbENvc3QsXG4gICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICBjb25maWRlbmNlOiAnbWVkaXVtJyxcbiAgICAgIGFzc3VtcHRpb25zOiBbXG4gICAgICAgIGAke2F0dGFjaG1lbnRzfSBhdHRhY2htZW50cyDDlyAkJHthdHRhY2htZW50UmF0ZS50b0ZpeGVkKDQpfS9ob3VyIMOXICR7dGhpcy5IT1VSU19QRVJfTU9OVEh9aCA9ICQke2F0dGFjaG1lbnRDb3N0LnRvRml4ZWQoMil9L21vbnRoYCxcbiAgICAgICAgYERhdGEgcHJvY2Vzc2luZzogJHttb250aGx5RGF0YUdCfSBHQiDDlyAkJHtkYXRhUHJvY2Vzc2luZ1JhdGUudG9GaXhlZCg0KX0vR0IgPSAkJHtkYXRhUHJvY2Vzc2luZ0Nvc3QudG9GaXhlZCgyKX0vbW9udGhgLFxuICAgICAgICAuLi4odXNlZEZhbGxiYWNrID8gW2BVc2luZyBmYWxsYmFjayBwcmljaW5nIChBUEkgZGF0YSBub3QgYXZhaWxhYmxlIGZvciByZWdpb24gJHtyZWdpb259KWBdIDogW10pLFxuICAgICAgXSxcbiAgICB9O1xuICB9XG59XG4iXX0=
@@ -1 +1 @@
1
- v0.1.39
1
+ v0.1.41