@electrolux-oss/plugin-infrawallet-backend 1.1.0-20251216093006-79b0013 → 1.1.0-20260112100533-68a81f8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cost-clients/DatadogClient.cjs.js +47 -26
- package/dist/cost-clients/DatadogClient.cjs.js.map +1 -1
- package/dist/cost-clients/InfraWalletClient.cjs.js +13 -0
- package/dist/cost-clients/InfraWalletClient.cjs.js.map +1 -1
- package/dist/service/router.cjs.js +7 -3
- package/dist/service/router.cjs.js.map +1 -1
- package/package.json +1 -1
|
@@ -89,21 +89,22 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
|
|
|
89
89
|
}
|
|
90
90
|
async fetchCosts(integrationConfig, client, query) {
|
|
91
91
|
const costData = [];
|
|
92
|
-
const startTime = moment__default.default(parseInt(query.startTime, 10));
|
|
93
|
-
const endTime = moment__default.default(parseInt(query.endTime, 10));
|
|
94
|
-
const
|
|
95
|
-
if (startTime.isBefore(
|
|
96
|
-
const historicalEndTime = moment__default.default.min(endTime,
|
|
97
|
-
const maxMonthRange =
|
|
92
|
+
const startTime = moment__default.default.utc(parseInt(query.startTime, 10)).startOf("month");
|
|
93
|
+
const endTime = moment__default.default.utc(parseInt(query.endTime, 10)).startOf("month");
|
|
94
|
+
const historicalCutoff = moment__default.default.utc().startOf("month").subtract(2, "months");
|
|
95
|
+
if (startTime.isBefore(historicalCutoff)) {
|
|
96
|
+
const historicalEndTime = moment__default.default.min(endTime, historicalCutoff.clone().subtract(1, "month"));
|
|
97
|
+
const maxMonthRange = 3;
|
|
98
98
|
let chunkStart = startTime.clone();
|
|
99
|
-
while (chunkStart.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
historicalEndTime.clone()
|
|
103
|
-
|
|
99
|
+
while (chunkStart.isSameOrBefore(historicalEndTime)) {
|
|
100
|
+
let chunkEnd = chunkStart.clone().add(maxMonthRange - 1, "months");
|
|
101
|
+
if (chunkEnd.isAfter(historicalEndTime)) {
|
|
102
|
+
chunkEnd = historicalEndTime.clone();
|
|
103
|
+
}
|
|
104
|
+
const apiEndMonth = chunkEnd.clone().add(1, "month");
|
|
104
105
|
const historicalCost = await client.getHistoricalCostByOrg({
|
|
105
106
|
startMonth: chunkStart,
|
|
106
|
-
endMonth:
|
|
107
|
+
endMonth: apiEndMonth,
|
|
107
108
|
view: "sub-org"
|
|
108
109
|
});
|
|
109
110
|
try {
|
|
@@ -120,17 +121,15 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
|
|
|
120
121
|
if (historicalCost.data) {
|
|
121
122
|
costData.push(...historicalCost.data);
|
|
122
123
|
}
|
|
123
|
-
chunkStart =
|
|
124
|
+
chunkStart = chunkStart.clone().add(maxMonthRange, "months");
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
|
-
if (endTime.isSameOrAfter(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
estimatedCostStartTime = firstDayOfLastMonth;
|
|
130
|
-
}
|
|
127
|
+
if (endTime.isSameOrAfter(historicalCutoff)) {
|
|
128
|
+
const estimatedStartTime = moment__default.default.max(startTime, historicalCutoff);
|
|
129
|
+
const apiEndTime = endTime.clone().add(1, "month");
|
|
131
130
|
const estimatedCost = await client.getEstimatedCostByOrg({
|
|
132
|
-
startMonth:
|
|
133
|
-
endMonth:
|
|
131
|
+
startMonth: estimatedStartTime,
|
|
132
|
+
endMonth: apiEndTime,
|
|
134
133
|
view: "sub-org"
|
|
135
134
|
});
|
|
136
135
|
try {
|
|
@@ -152,12 +151,13 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
|
|
|
152
151
|
if (query.granularity === consts.GRANULARITY.MONTHLY) {
|
|
153
152
|
costData.forEach((costByOrg) => {
|
|
154
153
|
const orgName = costByOrg.attributes?.orgName;
|
|
155
|
-
|
|
154
|
+
const date = costByOrg.attributes?.date;
|
|
155
|
+
if (!this.evaluateIntegrationFilters(orgName, integrationConfig) || !date) {
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
158
158
|
costs.push({
|
|
159
159
|
orgName,
|
|
160
|
-
date
|
|
160
|
+
date,
|
|
161
161
|
// only keep cost breakdown
|
|
162
162
|
charges: costByOrg.attributes?.charges?.filter((charge) => charge.chargeType !== "total")
|
|
163
163
|
});
|
|
@@ -165,10 +165,12 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
|
|
|
165
165
|
} else {
|
|
166
166
|
costData.forEach((costByOrg) => {
|
|
167
167
|
const orgName = costByOrg.attributes?.orgName;
|
|
168
|
-
|
|
168
|
+
const date = costByOrg.attributes?.date;
|
|
169
|
+
if (!this.evaluateIntegrationFilters(orgName, integrationConfig) || !date) {
|
|
169
170
|
return;
|
|
170
171
|
}
|
|
171
|
-
const
|
|
172
|
+
const utcDate = moment__default.default.utc(date);
|
|
173
|
+
const daysInMonth = utcDate.daysInMonth();
|
|
172
174
|
costByOrg.attributes?.charges?.forEach((charge) => {
|
|
173
175
|
if (charge.chargeType === "total") {
|
|
174
176
|
return;
|
|
@@ -176,7 +178,7 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
|
|
|
176
178
|
for (let i = 0; i < daysInMonth; i++) {
|
|
177
179
|
const dailyCost = {
|
|
178
180
|
orgName,
|
|
179
|
-
date:
|
|
181
|
+
date: utcDate.clone().add(i, "d"),
|
|
180
182
|
charges: [
|
|
181
183
|
{
|
|
182
184
|
productName: charge.productName,
|
|
@@ -192,6 +194,25 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
|
|
|
192
194
|
}
|
|
193
195
|
return costs;
|
|
194
196
|
}
|
|
197
|
+
async fetchForecast(integrationConfig) {
|
|
198
|
+
const client = await this.initCloudClient(integrationConfig);
|
|
199
|
+
let totalProjectedCost = 0;
|
|
200
|
+
const response = await client.getProjectedCost({
|
|
201
|
+
view: "sub-org"
|
|
202
|
+
});
|
|
203
|
+
if (!response.data) {
|
|
204
|
+
return totalProjectedCost;
|
|
205
|
+
}
|
|
206
|
+
response.data.forEach((item) => {
|
|
207
|
+
const attributes = item.attributes;
|
|
208
|
+
const orgName = attributes?.orgName;
|
|
209
|
+
const projectedTotal = attributes?.projectedTotalCost;
|
|
210
|
+
if (orgName && projectedTotal !== void 0 && this.evaluateIntegrationFilters(orgName, integrationConfig)) {
|
|
211
|
+
totalProjectedCost += projectedTotal;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
return totalProjectedCost;
|
|
215
|
+
}
|
|
195
216
|
async transformCostsData(subAccountConfig, query, costResponse) {
|
|
196
217
|
const tags = subAccountConfig.getOptionalStringArray("tags");
|
|
197
218
|
const tagKeyValues = {};
|
|
@@ -219,7 +240,7 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
|
|
|
219
240
|
if (query.granularity === consts.GRANULARITY.DAILY) {
|
|
220
241
|
periodFormat = "YYYY-MM-DD";
|
|
221
242
|
}
|
|
222
|
-
const dateObj = moment__default.default(costByOrg.date);
|
|
243
|
+
const dateObj = moment__default.default.utc(costByOrg.date);
|
|
223
244
|
if (!dateObj.isValid()) {
|
|
224
245
|
filteredOutInvalidDate++;
|
|
225
246
|
return accumulator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatadogClient.cjs.js","sources":["../../src/cost-clients/DatadogClient.ts"],"sourcesContent":["import { CacheService, DatabaseService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { v2 as datadogApiV2, client as datadogClient } from '@datadog/datadog-api-client';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { CLOUD_PROVIDER, GRANULARITY, PROVIDER_TYPE } from '../service/consts';\nimport { parseCost } from '../service/functions';\nimport { CostQuery, Report } from '../service/types';\nimport { InfraWalletClient } from './InfraWalletClient';\nimport { DatadogCostByOrgResponseSchema } from '../schemas/DatadogBilling';\nimport { ZodError } from 'zod';\n\nexport class DatadogClient extends InfraWalletClient {\n static create(config: Config, database: DatabaseService, cache: CacheService, logger: LoggerService) {\n return new DatadogClient(CLOUD_PROVIDER.DATADOG, config, database, cache, logger);\n }\n\n protected convertServiceName(serviceName: string): string {\n let convertedName = serviceName;\n\n // Datadog doesn't have this documented offically, raise a PR if any service is missed\n const aliases = new Map<string, string>([\n ['apm_host', 'APM Hosts'],\n ['apm_host_enterprise', 'APM Enterprise Hosts'],\n ['application_vulnerability_management_oss_host', 'Application Security - SCA Host'],\n ['application_security_host', 'ASM - Threat Management Hosts'],\n ['audit_trail', 'Audit Trail'],\n ['ci_pipeline', 'CI Visibility Committers'],\n ['ci_pipeline_indexed_spans', 'CI Visibility Spans'],\n ['cloud_cost_management', 'Cloud Cost Hosts'],\n ['cspm_container', 'Cloud Security Management Containers Pro'],\n ['cspm_host', 'Cloud Security Management Hosts Pro'],\n ['csm_host_pro', 'Cloud Security Management Hosts Pro'],\n ['cws_host', 'Cloud Workload Security Hosts'],\n ['infra_container', 'Containers'],\n ['infra_container_excl_agent', 'Containers'],\n ['timeseries', 'Custom Metrics'],\n ['error_tracking', 'Error Tracking'],\n ['incident_management', 'Incident Management'],\n ['logs_indexed_15day', 'Indexed Logs (15-day Retention)'],\n ['logs_indexed_180day', 'Indexed Logs (180-day Retention)'],\n ['logs_indexed_1day', 'Indexed Logs (1-day Retention)'],\n ['logs_indexed_30day', 'Indexed Logs (30-day Retention)'],\n ['logs_indexed_360day', 'Indexed Logs (360-day Retention)'],\n ['logs_indexed_3day', 'Indexed Logs (3-day Retention)'],\n ['logs_indexed_45day', 'Indexed Logs (45-day Retention)'],\n ['logs_indexed_60day', 'Indexed Logs (60-day Retention)'],\n ['logs_indexed_7day', 'Indexed Logs (7-day Retention)'],\n ['logs_indexed_90day', 'Indexed Logs (90-day Retention)'],\n ['apm_trace_search', 'Indexed Spans'],\n ['infra_host', 'Infra Hosts'],\n ['logs_ingested', 'Ingested Logs'],\n ['ingested_spans', 'Ingested Spans'],\n ['iot', 'IoT Devices'],\n ['npm_host', 'Network Hosts'],\n ['prof_container', 'Profiled Containers'],\n ['prof_host', 'Profiled Hosts'],\n ['rum_lite', 'RUM Sessions'],\n ['rum_replay', 'RUM with Session Replay Sessions'],\n ['siem_indexed', 'Security Analyzed and Indexed Logs'],\n ['sensitive_data_scanner', 'Sensitive Data Scanner'],\n ['serverless_apps', 'Serverless App Instances'],\n ['serverless_apm', 'Serverless Traced Invocations'],\n ['serverless_infra', 'Serverless Workload Functions'],\n ['siem', 'SIEM - Analyzed Logs'],\n ['synthetics_api_tests', 'Synthetics API Test Runs'],\n ['synthetics_browser_checks', 'Synthetics Browser Test Runs'],\n ['ci_testing', 'Test Visibility Committers'],\n ['ci_test_indexed_spans', 'Test Visibility Spans'],\n ]);\n\n if (aliases.has(convertedName)) {\n convertedName = aliases.get(convertedName) || convertedName;\n }\n\n return `${this.provider}/${convertedName}`;\n }\n\n protected async initCloudClient(integrationConfig: any): Promise<any> {\n const apiKey = integrationConfig.getString('apiKey');\n const applicationKey = integrationConfig.getString('applicationKey');\n const ddSite = integrationConfig.getString('ddSite');\n const configuration = datadogClient.createConfiguration({\n baseServer: new datadogClient.BaseServerConfiguration(ddSite, {}),\n authMethods: {\n apiKeyAuth: apiKey,\n appKeyAuth: applicationKey,\n },\n });\n const client = new datadogApiV2.UsageMeteringApi(configuration);\n return client;\n }\n\n protected async fetchCosts(integrationConfig: Config, client: any, query: CostQuery): Promise<any> {\n const costData: datadogApiV2.CostByOrg[] = [];\n const startTime = moment(parseInt(query.startTime, 10));\n const endTime = moment(parseInt(query.endTime, 10));\n const firstDayOfLastMonth = moment().subtract(1, 'M').startOf('M');\n\n // check if costs prior to 2 months ago are in query, if yes, use historical_cost API\n // https://docs.datadoghq.com/api/latest/usage-metering/#get-historical-cost-across-your-account\n if (startTime.isBefore(firstDayOfLastMonth)) {\n const historicalEndTime = moment.min(endTime, firstDayOfLastMonth.clone().subtract(1, 'd'));\n const maxMonthRange = 2;\n let chunkStart = startTime.clone();\n\n while (chunkStart.isBefore(historicalEndTime)) {\n const chunkEnd = moment.min(\n chunkStart.clone().add(maxMonthRange, 'months').subtract(1, 'day'),\n historicalEndTime.clone(),\n );\n\n const historicalCost: datadogApiV2.CostByOrgResponse = await client.getHistoricalCostByOrg({\n startMonth: chunkStart,\n endMonth: chunkEnd,\n view: 'sub-org',\n });\n\n try {\n DatadogCostByOrgResponseSchema.parse(historicalCost);\n this.logger.debug(`Datadog historical cost response validation passed`);\n } catch (error) {\n if (error instanceof ZodError) {\n this.logger.warn(`Datadog historical cost response validation failed: ${error.message}`);\n this.logger.debug(`Sample validation errors: ${JSON.stringify(error.errors.slice(0, 3))}`);\n } else {\n this.logger.warn(`Unexpected validation error: ${error.message}`);\n }\n }\n\n if (historicalCost.data) {\n costData.push(...historicalCost.data);\n }\n\n chunkStart = chunkEnd.clone().add(1, 'day').startOf('month');\n }\n }\n\n // check if current/last month costs are in query, if yes, use estimated_cost API\n // https://docs.datadoghq.com/api/latest/usage-metering/#get-estimated-cost-across-your-account\n if (endTime.isSameOrAfter(firstDayOfLastMonth)) {\n let estimatedCostStartTime = startTime;\n if (startTime.isBefore(firstDayOfLastMonth)) {\n estimatedCostStartTime = firstDayOfLastMonth;\n }\n\n const estimatedCost: datadogApiV2.CostByOrgResponse = await client.getEstimatedCostByOrg({\n startMonth: estimatedCostStartTime,\n endMonth: endTime,\n view: 'sub-org',\n });\n\n try {\n DatadogCostByOrgResponseSchema.parse(estimatedCost);\n this.logger.debug(`Datadog estimated cost response validation passed`);\n } catch (error) {\n if (error instanceof ZodError) {\n this.logger.warn(`Datadog estimated cost response validation failed: ${error.message}`);\n this.logger.debug(`Sample validation errors: ${JSON.stringify(error.errors.slice(0, 3))}`);\n } else {\n this.logger.warn(`Unexpected validation error: ${error.message}`);\n }\n }\n\n if (estimatedCost.data) {\n costData.push(...estimatedCost.data);\n }\n }\n\n const costs: any[] = [];\n\n if (query.granularity === GRANULARITY.MONTHLY) {\n costData.forEach(costByOrg => {\n const orgName = costByOrg.attributes?.orgName as string;\n if (!this.evaluateIntegrationFilters(orgName, integrationConfig)) {\n return;\n }\n\n costs.push({\n orgName: orgName,\n date: costByOrg.attributes?.date,\n // only keep cost breakdown\n charges: costByOrg.attributes?.charges?.filter(charge => charge.chargeType !== 'total'),\n });\n });\n } else {\n // Datadog doesn't provide daily costs based on usage, so we allocate monthly costs evenly by day\n costData.forEach(costByOrg => {\n const orgName = costByOrg.attributes?.orgName as string;\n if (!this.evaluateIntegrationFilters(orgName, integrationConfig)) {\n return;\n }\n\n const daysInMonth = moment(costByOrg.attributes?.date).daysInMonth();\n costByOrg.attributes?.charges?.forEach(charge => {\n if (charge.chargeType === 'total') {\n // only keep cost breakdown\n return;\n }\n\n for (let i = 0; i < daysInMonth; i++) {\n const dailyCost = {\n orgName: orgName,\n date: moment(costByOrg.attributes?.date).add(i, 'd'),\n charges: [\n {\n productName: charge.productName,\n cost: (charge.cost || 0) / daysInMonth,\n chargeType: charge.chargeType,\n },\n ],\n };\n costs.push(dailyCost);\n }\n });\n });\n }\n\n return costs;\n }\n\n protected async transformCostsData(subAccountConfig: Config, query: CostQuery, costResponse: any): Promise<Report[]> {\n const tags = subAccountConfig.getOptionalStringArray('tags');\n const tagKeyValues: { [key: string]: string } = {};\n tags?.forEach(tag => {\n const [k, v] = tag.split(':');\n tagKeyValues[k.trim()] = v.trim();\n });\n\n // Initialize tracking variables\n let processedRecords = 0;\n let filteredOutZeroAmount = 0;\n let filteredOutMissingFields = 0;\n let filteredOutInvalidDate = 0;\n const filteredOutTimeRange = 0;\n const uniqueKeys = new Set<string>();\n const totalRecords = costResponse?.length || 0;\n\n const transformedData = reduce(\n costResponse,\n (accumulator: { [key: string]: Report }, costByOrg) => {\n const account = costByOrg.orgName;\n const charges = costByOrg.charges;\n\n // Check for missing fields\n if (!account || !costByOrg.date) {\n filteredOutMissingFields++;\n return accumulator;\n }\n\n let periodFormat = 'YYYY-MM';\n if (query.granularity === GRANULARITY.DAILY) {\n periodFormat = 'YYYY-MM-DD';\n }\n\n const dateObj = moment(costByOrg.date);\n if (!dateObj.isValid()) {\n filteredOutInvalidDate++;\n return accumulator;\n }\n\n const period = dateObj.format(periodFormat);\n\n if (charges) {\n charges.forEach((charge: datadogApiV2.ChargebackBreakdown) => {\n const productName = charge.productName;\n const cost = charge.cost;\n\n // Check for missing fields\n if (!productName || cost === undefined || cost === null) {\n filteredOutMissingFields++;\n return;\n }\n\n const amount = parseCost(cost);\n\n // Check for zero amount\n if (amount === 0) {\n filteredOutZeroAmount++;\n return;\n }\n\n const keyName = `${account}->${productName} (${charge.chargeType})`;\n\n if (!accumulator[keyName]) {\n uniqueKeys.add(keyName);\n accumulator[keyName] = {\n id: keyName,\n account: `${this.provider}/${account}`,\n service: `${this.convertServiceName(productName as string)} (${charge.chargeType})`,\n category: 'Observability',\n provider: this.provider,\n providerType: PROVIDER_TYPE.INTEGRATION,\n reports: {},\n ...tagKeyValues,\n };\n }\n\n accumulator[keyName].reports[period] = amount;\n processedRecords++;\n });\n }\n\n return accumulator;\n },\n {},\n );\n\n this.logTransformationSummary({\n processed: processedRecords,\n uniqueReports: uniqueKeys.size,\n zeroAmount: filteredOutZeroAmount,\n missingFields: filteredOutMissingFields,\n invalidDate: filteredOutInvalidDate,\n timeRange: filteredOutTimeRange,\n totalRecords,\n });\n\n return Object.values(transformedData);\n }\n}\n"],"names":["InfraWalletClient","CLOUD_PROVIDER","datadogClient","datadogApiV2","moment","DatadogCostByOrgResponseSchema","ZodError","GRANULARITY","reduce","parseCost","PROVIDER_TYPE"],"mappings":";;;;;;;;;;;;;;;AAYO,MAAM,sBAAsBA,mCAAA,CAAkB;AAAA,EACnD,OAAO,MAAA,CAAO,MAAA,EAAgB,QAAA,EAA2B,OAAqB,MAAA,EAAuB;AACnG,IAAA,OAAO,IAAI,aAAA,CAAcC,qBAAA,CAAe,SAAS,MAAA,EAAQ,QAAA,EAAU,OAAO,MAAM,CAAA;AAAA;AAClF,EAEU,mBAAmB,WAAA,EAA6B;AACxD,IAAA,IAAI,aAAA,GAAgB,WAAA;AAGpB,IAAA,MAAM,OAAA,uBAAc,GAAA,CAAoB;AAAA,MACtC,CAAC,YAAY,WAAW,CAAA;AAAA,MACxB,CAAC,uBAAuB,sBAAsB,CAAA;AAAA,MAC9C,CAAC,iDAAiD,iCAAiC,CAAA;AAAA,MACnF,CAAC,6BAA6B,+BAA+B,CAAA;AAAA,MAC7D,CAAC,eAAe,aAAa,CAAA;AAAA,MAC7B,CAAC,eAAe,0BAA0B,CAAA;AAAA,MAC1C,CAAC,6BAA6B,qBAAqB,CAAA;AAAA,MACnD,CAAC,yBAAyB,kBAAkB,CAAA;AAAA,MAC5C,CAAC,kBAAkB,0CAA0C,CAAA;AAAA,MAC7D,CAAC,aAAa,qCAAqC,CAAA;AAAA,MACnD,CAAC,gBAAgB,qCAAqC,CAAA;AAAA,MACtD,CAAC,YAAY,+BAA+B,CAAA;AAAA,MAC5C,CAAC,mBAAmB,YAAY,CAAA;AAAA,MAChC,CAAC,8BAA8B,YAAY,CAAA;AAAA,MAC3C,CAAC,cAAc,gBAAgB,CAAA;AAAA,MAC/B,CAAC,kBAAkB,gBAAgB,CAAA;AAAA,MACnC,CAAC,uBAAuB,qBAAqB,CAAA;AAAA,MAC7C,CAAC,sBAAsB,iCAAiC,CAAA;AAAA,MACxD,CAAC,uBAAuB,kCAAkC,CAAA;AAAA,MAC1D,CAAC,qBAAqB,gCAAgC,CAAA;AAAA,MACtD,CAAC,sBAAsB,iCAAiC,CAAA;AAAA,MACxD,CAAC,uBAAuB,kCAAkC,CAAA;AAAA,MAC1D,CAAC,qBAAqB,gCAAgC,CAAA;AAAA,MACtD,CAAC,sBAAsB,iCAAiC,CAAA;AAAA,MACxD,CAAC,sBAAsB,iCAAiC,CAAA;AAAA,MACxD,CAAC,qBAAqB,gCAAgC,CAAA;AAAA,MACtD,CAAC,sBAAsB,iCAAiC,CAAA;AAAA,MACxD,CAAC,oBAAoB,eAAe,CAAA;AAAA,MACpC,CAAC,cAAc,aAAa,CAAA;AAAA,MAC5B,CAAC,iBAAiB,eAAe,CAAA;AAAA,MACjC,CAAC,kBAAkB,gBAAgB,CAAA;AAAA,MACnC,CAAC,OAAO,aAAa,CAAA;AAAA,MACrB,CAAC,YAAY,eAAe,CAAA;AAAA,MAC5B,CAAC,kBAAkB,qBAAqB,CAAA;AAAA,MACxC,CAAC,aAAa,gBAAgB,CAAA;AAAA,MAC9B,CAAC,YAAY,cAAc,CAAA;AAAA,MAC3B,CAAC,cAAc,kCAAkC,CAAA;AAAA,MACjD,CAAC,gBAAgB,oCAAoC,CAAA;AAAA,MACrD,CAAC,0BAA0B,wBAAwB,CAAA;AAAA,MACnD,CAAC,mBAAmB,0BAA0B,CAAA;AAAA,MAC9C,CAAC,kBAAkB,+BAA+B,CAAA;AAAA,MAClD,CAAC,oBAAoB,+BAA+B,CAAA;AAAA,MACpD,CAAC,QAAQ,sBAAsB,CAAA;AAAA,MAC/B,CAAC,wBAAwB,0BAA0B,CAAA;AAAA,MACnD,CAAC,6BAA6B,8BAA8B,CAAA;AAAA,MAC5D,CAAC,cAAc,4BAA4B,CAAA;AAAA,MAC3C,CAAC,yBAAyB,uBAAuB;AAAA,KAClD,CAAA;AAED,IAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,aAAa,CAAA,EAAG;AAC9B,MAAA,aAAA,GAAgB,OAAA,CAAQ,GAAA,CAAI,aAAa,CAAA,IAAK,aAAA;AAAA;AAGhD,IAAA,OAAO,CAAA,EAAG,IAAA,CAAK,QAAQ,CAAA,CAAA,EAAI,aAAa,CAAA,CAAA;AAAA;AAC1C,EAEA,MAAgB,gBAAgB,iBAAA,EAAsC;AACpE,IAAA,MAAM,MAAA,GAAS,iBAAA,CAAkB,SAAA,CAAU,QAAQ,CAAA;AACnD,IAAA,MAAM,cAAA,GAAiB,iBAAA,CAAkB,SAAA,CAAU,gBAAgB,CAAA;AACnE,IAAA,MAAM,MAAA,GAAS,iBAAA,CAAkB,SAAA,CAAU,QAAQ,CAAA;AACnD,IAAA,MAAM,aAAA,GAAgBC,wBAAc,mBAAA,CAAoB;AAAA,MACtD,YAAY,IAAIA,uBAAA,CAAc,uBAAA,CAAwB,MAAA,EAAQ,EAAE,CAAA;AAAA,MAChE,WAAA,EAAa;AAAA,QACX,UAAA,EAAY,MAAA;AAAA,QACZ,UAAA,EAAY;AAAA;AACd,KACD,CAAA;AACD,IAAA,MAAM,MAAA,GAAS,IAAIC,mBAAA,CAAa,gBAAA,CAAiB,aAAa,CAAA;AAC9D,IAAA,OAAO,MAAA;AAAA;AACT,EAEA,MAAgB,UAAA,CAAW,iBAAA,EAA2B,MAAA,EAAa,KAAA,EAAgC;AACjG,IAAA,MAAM,WAAqC,EAAC;AAC5C,IAAA,MAAM,YAAYC,uBAAA,CAAO,QAAA,CAAS,KAAA,CAAM,SAAA,EAAW,EAAE,CAAC,CAAA;AACtD,IAAA,MAAM,UAAUA,uBAAA,CAAO,QAAA,CAAS,KAAA,CAAM,OAAA,EAAS,EAAE,CAAC,CAAA;AAClD,IAAA,MAAM,mBAAA,GAAsBA,yBAAO,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA,CAAE,QAAQ,GAAG,CAAA;AAIjE,IAAA,IAAI,SAAA,CAAU,QAAA,CAAS,mBAAmB,CAAA,EAAG;AAC3C,MAAA,MAAM,iBAAA,GAAoBA,uBAAA,CAAO,GAAA,CAAI,OAAA,EAAS,mBAAA,CAAoB,OAAM,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA;AAC1F,MAAA,MAAM,aAAA,GAAgB,CAAA;AACtB,MAAA,IAAI,UAAA,GAAa,UAAU,KAAA,EAAM;AAEjC,MAAA,OAAO,UAAA,CAAW,QAAA,CAAS,iBAAiB,CAAA,EAAG;AAC7C,QAAA,MAAM,WAAWA,uBAAA,CAAO,GAAA;AAAA,UACtB,UAAA,CAAW,OAAM,CAAE,GAAA,CAAI,eAAe,QAAQ,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,KAAK,CAAA;AAAA,UACjE,kBAAkB,KAAA;AAAM,SAC1B;AAEA,QAAA,MAAM,cAAA,GAAiD,MAAM,MAAA,CAAO,sBAAA,CAAuB;AAAA,UACzF,UAAA,EAAY,UAAA;AAAA,UACZ,QAAA,EAAU,QAAA;AAAA,UACV,IAAA,EAAM;AAAA,SACP,CAAA;AAED,QAAA,IAAI;AACF,UAAAC,6CAAA,CAA+B,MAAM,cAAc,CAAA;AACnD,UAAA,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,kDAAA,CAAoD,CAAA;AAAA,iBAC/D,KAAA,EAAO;AACd,UAAA,IAAI,iBAAiBC,YAAA,EAAU;AAC7B,YAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAA,oDAAA,EAAuD,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AACvF,YAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAA,0BAAA,EAA6B,IAAA,CAAK,SAAA,CAAU,KAAA,CAAM,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,WAC3F,MAAO;AACL,YAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAA,6BAAA,EAAgC,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AAAA;AAClE;AAGF,QAAA,IAAI,eAAe,IAAA,EAAM;AACvB,UAAA,QAAA,CAAS,IAAA,CAAK,GAAG,cAAA,CAAe,IAAI,CAAA;AAAA;AAGtC,QAAA,UAAA,GAAa,QAAA,CAAS,OAAM,CAAE,GAAA,CAAI,GAAG,KAAK,CAAA,CAAE,QAAQ,OAAO,CAAA;AAAA;AAC7D;AAKF,IAAA,IAAI,OAAA,CAAQ,aAAA,CAAc,mBAAmB,CAAA,EAAG;AAC9C,MAAA,IAAI,sBAAA,GAAyB,SAAA;AAC7B,MAAA,IAAI,SAAA,CAAU,QAAA,CAAS,mBAAmB,CAAA,EAAG;AAC3C,QAAA,sBAAA,GAAyB,mBAAA;AAAA;AAG3B,MAAA,MAAM,aAAA,GAAgD,MAAM,MAAA,CAAO,qBAAA,CAAsB;AAAA,QACvF,UAAA,EAAY,sBAAA;AAAA,QACZ,QAAA,EAAU,OAAA;AAAA,QACV,IAAA,EAAM;AAAA,OACP,CAAA;AAED,MAAA,IAAI;AACF,QAAAD,6CAAA,CAA+B,MAAM,aAAa,CAAA;AAClD,QAAA,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,iDAAA,CAAmD,CAAA;AAAA,eAC9D,KAAA,EAAO;AACd,QAAA,IAAI,iBAAiBC,YAAA,EAAU;AAC7B,UAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAA,mDAAA,EAAsD,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AACtF,UAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAA,0BAAA,EAA6B,IAAA,CAAK,SAAA,CAAU,KAAA,CAAM,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,SAC3F,MAAO;AACL,UAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAA,6BAAA,EAAgC,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AAAA;AAClE;AAGF,MAAA,IAAI,cAAc,IAAA,EAAM;AACtB,QAAA,QAAA,CAAS,IAAA,CAAK,GAAG,aAAA,CAAc,IAAI,CAAA;AAAA;AACrC;AAGF,IAAA,MAAM,QAAe,EAAC;AAEtB,IAAA,IAAI,KAAA,CAAM,WAAA,KAAgBC,kBAAA,CAAY,OAAA,EAAS;AAC7C,MAAA,QAAA,CAAS,QAAQ,CAAA,SAAA,KAAa;AAC5B,QAAA,MAAM,OAAA,GAAU,UAAU,UAAA,EAAY,OAAA;AACtC,QAAA,IAAI,CAAC,IAAA,CAAK,0BAAA,CAA2B,OAAA,EAAS,iBAAiB,CAAA,EAAG;AAChE,UAAA;AAAA;AAGF,QAAA,KAAA,CAAM,IAAA,CAAK;AAAA,UACT,OAAA;AAAA,UACA,IAAA,EAAM,UAAU,UAAA,EAAY,IAAA;AAAA;AAAA,UAE5B,OAAA,EAAS,UAAU,UAAA,EAAY,OAAA,EAAS,OAAO,CAAA,MAAA,KAAU,MAAA,CAAO,eAAe,OAAO;AAAA,SACvF,CAAA;AAAA,OACF,CAAA;AAAA,KACH,MAAO;AAEL,MAAA,QAAA,CAAS,QAAQ,CAAA,SAAA,KAAa;AAC5B,QAAA,MAAM,OAAA,GAAU,UAAU,UAAA,EAAY,OAAA;AACtC,QAAA,IAAI,CAAC,IAAA,CAAK,0BAAA,CAA2B,OAAA,EAAS,iBAAiB,CAAA,EAAG;AAChE,UAAA;AAAA;AAGF,QAAA,MAAM,cAAcH,uBAAA,CAAO,SAAA,CAAU,UAAA,EAAY,IAAI,EAAE,WAAA,EAAY;AACnE,QAAA,SAAA,CAAU,UAAA,EAAY,OAAA,EAAS,OAAA,CAAQ,CAAA,MAAA,KAAU;AAC/C,UAAA,IAAI,MAAA,CAAO,eAAe,OAAA,EAAS;AAEjC,YAAA;AAAA;AAGF,UAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,WAAA,EAAa,CAAA,EAAA,EAAK;AACpC,YAAA,MAAM,SAAA,GAAY;AAAA,cAChB,OAAA;AAAA,cACA,IAAA,EAAMA,wBAAO,SAAA,CAAU,UAAA,EAAY,IAAI,CAAA,CAAE,GAAA,CAAI,GAAG,GAAG,CAAA;AAAA,cACnD,OAAA,EAAS;AAAA,gBACP;AAAA,kBACE,aAAa,MAAA,CAAO,WAAA;AAAA,kBACpB,IAAA,EAAA,CAAO,MAAA,CAAO,IAAA,IAAQ,CAAA,IAAK,WAAA;AAAA,kBAC3B,YAAY,MAAA,CAAO;AAAA;AACrB;AACF,aACF;AACA,YAAA,KAAA,CAAM,KAAK,SAAS,CAAA;AAAA;AACtB,SACD,CAAA;AAAA,OACF,CAAA;AAAA;AAGH,IAAA,OAAO,KAAA;AAAA;AACT,EAEA,MAAgB,kBAAA,CAAmB,gBAAA,EAA0B,KAAA,EAAkB,YAAA,EAAsC;AACnH,IAAA,MAAM,IAAA,GAAO,gBAAA,CAAiB,sBAAA,CAAuB,MAAM,CAAA;AAC3D,IAAA,MAAM,eAA0C,EAAC;AACjD,IAAA,IAAA,EAAM,QAAQ,CAAA,GAAA,KAAO;AACnB,MAAA,MAAM,CAAC,CAAA,EAAG,CAAC,CAAA,GAAI,GAAA,CAAI,MAAM,GAAG,CAAA;AAC5B,MAAA,YAAA,CAAa,CAAA,CAAE,IAAA,EAAM,CAAA,GAAI,EAAE,IAAA,EAAK;AAAA,KACjC,CAAA;AAGD,IAAA,IAAI,gBAAA,GAAmB,CAAA;AACvB,IAAA,IAAI,qBAAA,GAAwB,CAAA;AAC5B,IAAA,IAAI,wBAAA,GAA2B,CAAA;AAC/B,IAAA,IAAI,sBAAA,GAAyB,CAAA;AAC7B,IAAA,MAAM,oBAAA,GAAuB,CAAA;AAC7B,IAAA,MAAM,UAAA,uBAAiB,GAAA,EAAY;AACnC,IAAA,MAAM,YAAA,GAAe,cAAc,MAAA,IAAU,CAAA;AAE7C,IAAA,MAAM,eAAA,GAAkBI,aAAA;AAAA,MACtB,YAAA;AAAA,MACA,CAAC,aAAwC,SAAA,KAAc;AACrD,QAAA,MAAM,UAAU,SAAA,CAAU,OAAA;AAC1B,QAAA,MAAM,UAAU,SAAA,CAAU,OAAA;AAG1B,QAAA,IAAI,CAAC,OAAA,IAAW,CAAC,SAAA,CAAU,IAAA,EAAM;AAC/B,UAAA,wBAAA,EAAA;AACA,UAAA,OAAO,WAAA;AAAA;AAGT,QAAA,IAAI,YAAA,GAAe,SAAA;AACnB,QAAA,IAAI,KAAA,CAAM,WAAA,KAAgBD,kBAAA,CAAY,KAAA,EAAO;AAC3C,UAAA,YAAA,GAAe,YAAA;AAAA;AAGjB,QAAA,MAAM,OAAA,GAAUH,uBAAA,CAAO,SAAA,CAAU,IAAI,CAAA;AACrC,QAAA,IAAI,CAAC,OAAA,CAAQ,OAAA,EAAQ,EAAG;AACtB,UAAA,sBAAA,EAAA;AACA,UAAA,OAAO,WAAA;AAAA;AAGT,QAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,CAAO,YAAY,CAAA;AAE1C,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,OAAA,CAAQ,OAAA,CAAQ,CAAC,MAAA,KAA6C;AAC5D,YAAA,MAAM,cAAc,MAAA,CAAO,WAAA;AAC3B,YAAA,MAAM,OAAO,MAAA,CAAO,IAAA;AAGpB,YAAA,IAAI,CAAC,WAAA,IAAe,IAAA,KAAS,MAAA,IAAa,SAAS,IAAA,EAAM;AACvD,cAAA,wBAAA,EAAA;AACA,cAAA;AAAA;AAGF,YAAA,MAAM,MAAA,GAASK,oBAAU,IAAI,CAAA;AAG7B,YAAA,IAAI,WAAW,CAAA,EAAG;AAChB,cAAA,qBAAA,EAAA;AACA,cAAA;AAAA;AAGF,YAAA,MAAM,UAAU,CAAA,EAAG,OAAO,KAAK,WAAW,CAAA,EAAA,EAAK,OAAO,UAAU,CAAA,CAAA,CAAA;AAEhE,YAAA,IAAI,CAAC,WAAA,CAAY,OAAO,CAAA,EAAG;AACzB,cAAA,UAAA,CAAW,IAAI,OAAO,CAAA;AACtB,cAAA,WAAA,CAAY,OAAO,CAAA,GAAI;AAAA,gBACrB,EAAA,EAAI,OAAA;AAAA,gBACJ,OAAA,EAAS,CAAA,EAAG,IAAA,CAAK,QAAQ,IAAI,OAAO,CAAA,CAAA;AAAA,gBACpC,OAAA,EAAS,GAAG,IAAA,CAAK,kBAAA,CAAmB,WAAqB,CAAC,CAAA,EAAA,EAAK,OAAO,UAAU,CAAA,CAAA,CAAA;AAAA,gBAChF,QAAA,EAAU,eAAA;AAAA,gBACV,UAAU,IAAA,CAAK,QAAA;AAAA,gBACf,cAAcC,oBAAA,CAAc,WAAA;AAAA,gBAC5B,SAAS,EAAC;AAAA,gBACV,GAAG;AAAA,eACL;AAAA;AAGF,YAAA,WAAA,CAAY,OAAO,CAAA,CAAE,OAAA,CAAQ,MAAM,CAAA,GAAI,MAAA;AACvC,YAAA,gBAAA,EAAA;AAAA,WACD,CAAA;AAAA;AAGH,QAAA,OAAO,WAAA;AAAA,OACT;AAAA,MACA;AAAC,KACH;AAEA,IAAA,IAAA,CAAK,wBAAA,CAAyB;AAAA,MAC5B,SAAA,EAAW,gBAAA;AAAA,MACX,eAAe,UAAA,CAAW,IAAA;AAAA,MAC1B,UAAA,EAAY,qBAAA;AAAA,MACZ,aAAA,EAAe,wBAAA;AAAA,MACf,WAAA,EAAa,sBAAA;AAAA,MACb,SAAA,EAAW,oBAAA;AAAA,MACX;AAAA,KACD,CAAA;AAED,IAAA,OAAO,MAAA,CAAO,OAAO,eAAe,CAAA;AAAA;AAExC;;;;"}
|
|
1
|
+
{"version":3,"file":"DatadogClient.cjs.js","sources":["../../src/cost-clients/DatadogClient.ts"],"sourcesContent":["import { CacheService, DatabaseService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { v2 as datadogApiV2, client as datadogClient } from '@datadog/datadog-api-client';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { CLOUD_PROVIDER, GRANULARITY, PROVIDER_TYPE } from '../service/consts';\nimport { parseCost } from '../service/functions';\nimport { CostQuery, Report } from '../service/types';\nimport { InfraWalletClient } from './InfraWalletClient';\nimport { DatadogCostByOrgResponseSchema } from '../schemas/DatadogBilling';\nimport { ZodError } from 'zod';\n\nexport class DatadogClient extends InfraWalletClient {\n static create(config: Config, database: DatabaseService, cache: CacheService, logger: LoggerService) {\n return new DatadogClient(CLOUD_PROVIDER.DATADOG, config, database, cache, logger);\n }\n\n protected convertServiceName(serviceName: string): string {\n let convertedName = serviceName;\n\n // Datadog doesn't have this documented offically, raise a PR if any service is missed\n const aliases = new Map<string, string>([\n ['apm_host', 'APM Hosts'],\n ['apm_host_enterprise', 'APM Enterprise Hosts'],\n ['application_vulnerability_management_oss_host', 'Application Security - SCA Host'],\n ['application_security_host', 'ASM - Threat Management Hosts'],\n ['audit_trail', 'Audit Trail'],\n ['ci_pipeline', 'CI Visibility Committers'],\n ['ci_pipeline_indexed_spans', 'CI Visibility Spans'],\n ['cloud_cost_management', 'Cloud Cost Hosts'],\n ['cspm_container', 'Cloud Security Management Containers Pro'],\n ['cspm_host', 'Cloud Security Management Hosts Pro'],\n ['csm_host_pro', 'Cloud Security Management Hosts Pro'],\n ['cws_host', 'Cloud Workload Security Hosts'],\n ['infra_container', 'Containers'],\n ['infra_container_excl_agent', 'Containers'],\n ['timeseries', 'Custom Metrics'],\n ['error_tracking', 'Error Tracking'],\n ['incident_management', 'Incident Management'],\n ['logs_indexed_15day', 'Indexed Logs (15-day Retention)'],\n ['logs_indexed_180day', 'Indexed Logs (180-day Retention)'],\n ['logs_indexed_1day', 'Indexed Logs (1-day Retention)'],\n ['logs_indexed_30day', 'Indexed Logs (30-day Retention)'],\n ['logs_indexed_360day', 'Indexed Logs (360-day Retention)'],\n ['logs_indexed_3day', 'Indexed Logs (3-day Retention)'],\n ['logs_indexed_45day', 'Indexed Logs (45-day Retention)'],\n ['logs_indexed_60day', 'Indexed Logs (60-day Retention)'],\n ['logs_indexed_7day', 'Indexed Logs (7-day Retention)'],\n ['logs_indexed_90day', 'Indexed Logs (90-day Retention)'],\n ['apm_trace_search', 'Indexed Spans'],\n ['infra_host', 'Infra Hosts'],\n ['logs_ingested', 'Ingested Logs'],\n ['ingested_spans', 'Ingested Spans'],\n ['iot', 'IoT Devices'],\n ['npm_host', 'Network Hosts'],\n ['prof_container', 'Profiled Containers'],\n ['prof_host', 'Profiled Hosts'],\n ['rum_lite', 'RUM Sessions'],\n ['rum_replay', 'RUM with Session Replay Sessions'],\n ['siem_indexed', 'Security Analyzed and Indexed Logs'],\n ['sensitive_data_scanner', 'Sensitive Data Scanner'],\n ['serverless_apps', 'Serverless App Instances'],\n ['serverless_apm', 'Serverless Traced Invocations'],\n ['serverless_infra', 'Serverless Workload Functions'],\n ['siem', 'SIEM - Analyzed Logs'],\n ['synthetics_api_tests', 'Synthetics API Test Runs'],\n ['synthetics_browser_checks', 'Synthetics Browser Test Runs'],\n ['ci_testing', 'Test Visibility Committers'],\n ['ci_test_indexed_spans', 'Test Visibility Spans'],\n ]);\n\n if (aliases.has(convertedName)) {\n convertedName = aliases.get(convertedName) || convertedName;\n }\n\n return `${this.provider}/${convertedName}`;\n }\n\n protected async initCloudClient(integrationConfig: any): Promise<any> {\n const apiKey = integrationConfig.getString('apiKey');\n const applicationKey = integrationConfig.getString('applicationKey');\n const ddSite = integrationConfig.getString('ddSite');\n const configuration = datadogClient.createConfiguration({\n baseServer: new datadogClient.BaseServerConfiguration(ddSite, {}),\n authMethods: {\n apiKeyAuth: apiKey,\n appKeyAuth: applicationKey,\n },\n });\n const client = new datadogApiV2.UsageMeteringApi(configuration);\n return client;\n }\n\n protected async fetchCosts(integrationConfig: Config, client: any, query: CostQuery): Promise<any> {\n const costData: datadogApiV2.CostByOrg[] = [];\n // Strict UTC to prevent month boundary drift\n const startTime = moment.utc(parseInt(query.startTime, 10)).startOf('month');\n const endTime = moment.utc(parseInt(query.endTime, 10)).startOf('month');\n const historicalCutoff = moment.utc().startOf('month').subtract(2, 'months');\n\n // check if costs prior to 2 months ago are in query, if yes, use historical_cost API\n // https://docs.datadoghq.com/api/latest/usage-metering/#get-historical-cost-across-your-account\n if (startTime.isBefore(historicalCutoff)) {\n const historicalEndTime = moment.min(endTime, historicalCutoff.clone().subtract(1, 'month'));\n // Datadog API quirk: To get data FOR a specific end month, the API request must include the NEXT month.\n const maxMonthRange = 3;\n let chunkStart = startTime.clone();\n\n while (chunkStart.isSameOrBefore(historicalEndTime)) {\n let chunkEnd = chunkStart.clone().add(maxMonthRange - 1, 'months');\n if (chunkEnd.isAfter(historicalEndTime)) {\n chunkEnd = historicalEndTime.clone();\n }\n\n const apiEndMonth = chunkEnd.clone().add(1, 'month');\n\n const historicalCost: datadogApiV2.CostByOrgResponse = await client.getHistoricalCostByOrg({\n startMonth: chunkStart,\n endMonth: apiEndMonth,\n view: 'sub-org',\n });\n\n try {\n DatadogCostByOrgResponseSchema.parse(historicalCost);\n this.logger.debug(`Datadog historical cost response validation passed`);\n } catch (error) {\n if (error instanceof ZodError) {\n this.logger.warn(`Datadog historical cost response validation failed: ${error.message}`);\n this.logger.debug(`Sample validation errors: ${JSON.stringify(error.errors.slice(0, 3))}`);\n } else {\n this.logger.warn(`Unexpected validation error: ${error.message}`);\n }\n }\n\n if (historicalCost.data) {\n costData.push(...historicalCost.data);\n }\n\n chunkStart = chunkStart.clone().add(maxMonthRange, 'months');\n }\n }\n\n // check if current/last month costs are in query, if yes, use estimated_cost API\n // https://docs.datadoghq.com/api/latest/usage-metering/#get-estimated-cost-across-your-account\n if (endTime.isSameOrAfter(historicalCutoff)) {\n const estimatedStartTime = moment.max(startTime, historicalCutoff);\n const apiEndTime = endTime.clone().add(1, 'month');\n\n const estimatedCost: datadogApiV2.CostByOrgResponse = await client.getEstimatedCostByOrg({\n startMonth: estimatedStartTime,\n endMonth: apiEndTime,\n view: 'sub-org',\n });\n\n try {\n DatadogCostByOrgResponseSchema.parse(estimatedCost);\n this.logger.debug(`Datadog estimated cost response validation passed`);\n } catch (error) {\n if (error instanceof ZodError) {\n this.logger.warn(`Datadog estimated cost response validation failed: ${error.message}`);\n this.logger.debug(`Sample validation errors: ${JSON.stringify(error.errors.slice(0, 3))}`);\n } else {\n this.logger.warn(`Unexpected validation error: ${error.message}`);\n }\n }\n\n if (estimatedCost.data) {\n costData.push(...estimatedCost.data);\n }\n }\n\n const costs: any[] = [];\n\n if (query.granularity === GRANULARITY.MONTHLY) {\n costData.forEach(costByOrg => {\n const orgName = costByOrg.attributes?.orgName as string;\n const date = costByOrg.attributes?.date;\n\n if (!this.evaluateIntegrationFilters(orgName, integrationConfig) || !date) {\n return;\n }\n\n costs.push({\n orgName: orgName,\n date: date,\n // only keep cost breakdown\n charges: costByOrg.attributes?.charges?.filter(charge => charge.chargeType !== 'total'),\n });\n });\n } else {\n // Datadog doesn't provide daily costs based on usage, so we allocate monthly costs evenly by day\n costData.forEach(costByOrg => {\n const orgName = costByOrg.attributes?.orgName as string;\n const date = costByOrg.attributes?.date;\n\n if (!this.evaluateIntegrationFilters(orgName, integrationConfig) || !date) {\n return;\n }\n\n const utcDate = moment.utc(date);\n const daysInMonth = utcDate.daysInMonth();\n\n costByOrg.attributes?.charges?.forEach(charge => {\n if (charge.chargeType === 'total') {\n // only keep cost breakdown\n return;\n }\n\n for (let i = 0; i < daysInMonth; i++) {\n const dailyCost = {\n orgName: orgName,\n date: utcDate.clone().add(i, 'd'),\n charges: [\n {\n productName: charge.productName,\n cost: (charge.cost || 0) / daysInMonth,\n chargeType: charge.chargeType,\n },\n ],\n };\n costs.push(dailyCost);\n }\n });\n });\n }\n\n return costs;\n }\n\n async fetchForecast(integrationConfig: Config): Promise<number> {\n const client = await this.initCloudClient(integrationConfig);\n let totalProjectedCost = 0;\n\n const response: datadogApiV2.ProjectedCostResponse = await client.getProjectedCost({\n view: 'sub-org',\n });\n\n if (!response.data) {\n return totalProjectedCost;\n }\n\n response.data.forEach(item => {\n const attributes = item.attributes;\n const orgName = attributes?.orgName;\n const projectedTotal = attributes?.projectedTotalCost;\n\n if (orgName && projectedTotal !== undefined && this.evaluateIntegrationFilters(orgName, integrationConfig)) {\n totalProjectedCost += projectedTotal;\n }\n });\n\n return totalProjectedCost;\n }\n\n protected async transformCostsData(subAccountConfig: Config, query: CostQuery, costResponse: any): Promise<Report[]> {\n const tags = subAccountConfig.getOptionalStringArray('tags');\n const tagKeyValues: { [key: string]: string } = {};\n tags?.forEach(tag => {\n const [k, v] = tag.split(':');\n tagKeyValues[k.trim()] = v.trim();\n });\n\n // Initialize tracking variables\n let processedRecords = 0;\n let filteredOutZeroAmount = 0;\n let filteredOutMissingFields = 0;\n let filteredOutInvalidDate = 0;\n const filteredOutTimeRange = 0;\n const uniqueKeys = new Set<string>();\n const totalRecords = costResponse?.length || 0;\n\n const transformedData = reduce(\n costResponse,\n (accumulator: { [key: string]: Report }, costByOrg) => {\n const account = costByOrg.orgName;\n const charges = costByOrg.charges;\n\n // Check for missing fields\n if (!account || !costByOrg.date) {\n filteredOutMissingFields++;\n return accumulator;\n }\n\n let periodFormat = 'YYYY-MM';\n if (query.granularity === GRANULARITY.DAILY) {\n periodFormat = 'YYYY-MM-DD';\n }\n\n const dateObj = moment.utc(costByOrg.date);\n if (!dateObj.isValid()) {\n filteredOutInvalidDate++;\n return accumulator;\n }\n\n const period = dateObj.format(periodFormat);\n\n if (charges) {\n charges.forEach((charge: datadogApiV2.ChargebackBreakdown) => {\n const productName = charge.productName;\n const cost = charge.cost;\n\n // Check for missing fields\n if (!productName || cost === undefined || cost === null) {\n filteredOutMissingFields++;\n return;\n }\n\n const amount = parseCost(cost);\n\n // Check for zero amount\n if (amount === 0) {\n filteredOutZeroAmount++;\n return;\n }\n\n const keyName = `${account}->${productName} (${charge.chargeType})`;\n\n if (!accumulator[keyName]) {\n uniqueKeys.add(keyName);\n accumulator[keyName] = {\n id: keyName,\n account: `${this.provider}/${account}`,\n service: `${this.convertServiceName(productName as string)} (${charge.chargeType})`,\n category: 'Observability',\n provider: this.provider,\n providerType: PROVIDER_TYPE.INTEGRATION,\n reports: {},\n ...tagKeyValues,\n };\n }\n\n accumulator[keyName].reports[period] = amount;\n processedRecords++;\n });\n }\n\n return accumulator;\n },\n {},\n );\n\n this.logTransformationSummary({\n processed: processedRecords,\n uniqueReports: uniqueKeys.size,\n zeroAmount: filteredOutZeroAmount,\n missingFields: filteredOutMissingFields,\n invalidDate: filteredOutInvalidDate,\n timeRange: filteredOutTimeRange,\n totalRecords,\n });\n\n return Object.values(transformedData);\n }\n}\n"],"names":["InfraWalletClient","CLOUD_PROVIDER","datadogClient","datadogApiV2","moment","DatadogCostByOrgResponseSchema","ZodError","GRANULARITY","reduce","parseCost","PROVIDER_TYPE"],"mappings":"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"}
|
|
@@ -60,6 +60,9 @@ class InfraWalletClient {
|
|
|
60
60
|
async fetchTagValues(_integrationConfig, _client, _query, _tagKey) {
|
|
61
61
|
return { tagValues: [], provider: this.provider };
|
|
62
62
|
}
|
|
63
|
+
async fetchForecast(_integrationConfig) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
63
66
|
logTransformationSummary(summary) {
|
|
64
67
|
functions.logTransformationSummary(this.logger, this.provider, summary);
|
|
65
68
|
}
|
|
@@ -182,7 +185,10 @@ class InfraWalletClient {
|
|
|
182
185
|
return { reports: [], errors: [] };
|
|
183
186
|
}
|
|
184
187
|
const results = [];
|
|
188
|
+
const forecasts = {};
|
|
185
189
|
const errors = [];
|
|
190
|
+
const now = /* @__PURE__ */ new Date();
|
|
191
|
+
const isCurrentMonthIncluded = query.granularity === consts.GRANULARITY.MONTHLY && parseInt(query.endTime, 10) >= new Date(now.getFullYear(), now.getMonth(), 1).getTime();
|
|
186
192
|
if (query.tags === "()" && query.groups === "" && autoloadCostData && this.provider !== consts.CLOUD_PROVIDER.MOCK) {
|
|
187
193
|
const reportsFromDatabase = await this.getCostReportsFromDatabase(query);
|
|
188
194
|
reportsFromDatabase.forEach((report) => {
|
|
@@ -216,6 +222,12 @@ class InfraWalletClient {
|
|
|
216
222
|
transformedReports.forEach((value) => {
|
|
217
223
|
results.push(value);
|
|
218
224
|
});
|
|
225
|
+
if (isCurrentMonthIncluded) {
|
|
226
|
+
const integrationForecast = await this.fetchForecast(integrationConfig);
|
|
227
|
+
if (integrationForecast !== null) {
|
|
228
|
+
forecasts[this.provider] = integrationForecast;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
219
231
|
} catch (e) {
|
|
220
232
|
this.logger.error(e);
|
|
221
233
|
errors.push({
|
|
@@ -231,6 +243,7 @@ class InfraWalletClient {
|
|
|
231
243
|
}
|
|
232
244
|
return {
|
|
233
245
|
reports: results,
|
|
246
|
+
forecasts,
|
|
234
247
|
errors
|
|
235
248
|
};
|
|
236
249
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfraWalletClient.cjs.js","sources":["../../src/cost-clients/InfraWalletClient.ts"],"sourcesContent":["import { CacheService, DatabaseService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { addMonths, endOfMonth, format, startOfMonth } from 'date-fns';\nimport { reduce } from 'lodash';\nimport { getWallet } from '../controllers/MetricSettingController';\nimport { CostItem, bulkInsertCostItems, countCostItems, getCostItems } from '../models/CostItem';\nimport {\n CACHE_CATEGORY,\n CLOUD_PROVIDER,\n GRANULARITY,\n NUMBER_OF_MONTHS_FETCHING_HISTORICAL_COSTS,\n PROVIDER_TYPE,\n} from '../service/consts';\nimport {\n getDefaultCacheTTL,\n getReportsFromCache,\n getTagKeysFromCache,\n getTagValuesFromCache,\n logTransformationSummary,\n setReportsToCache,\n setTagKeysToCache,\n setTagValuesToCache,\n tagExists,\n usageDateToPeriodString,\n} from '../service/functions';\nimport {\n ClientResponse,\n CloudProviderError,\n CostQuery,\n Filter,\n Report,\n Tag,\n TagsQuery,\n TagsResponse,\n TransformationSummary,\n Wallet,\n} from '../service/types';\n\nexport abstract class InfraWalletClient {\n constructor(\n protected readonly provider: CLOUD_PROVIDER,\n protected readonly config: Config,\n protected readonly database: DatabaseService,\n protected readonly cache: CacheService,\n protected readonly logger: LoggerService,\n ) {}\n\n protected convertServiceName(serviceName: string): string {\n return `${this.provider}/${serviceName}`;\n }\n\n protected evaluateIntegrationFilters(account: string, integrationConfig: Config): boolean {\n const filters: Filter[] = [];\n for (const filter of integrationConfig.getOptionalConfigArray('filters') || []) {\n filters.push({\n type: filter.getString('type'),\n attribute: filter.getString('attribute'),\n pattern: filter.getString('pattern'),\n });\n }\n return this.evaluateFilters(account, filters);\n }\n\n private evaluateFilters(account: string, filters: Filter[]): boolean {\n if (!filters || filters.length === 0) {\n // include if no filter\n return true;\n }\n\n let included = false;\n let hasIncludeFilter = false;\n\n for (const filter of filters) {\n const regex = new RegExp(filter.pattern);\n\n if (filter.type === 'exclude' && regex.test(account)) {\n // exclude immediately if an exclude filter matches\n return false;\n }\n\n if (filter.type === 'include') {\n hasIncludeFilter = true;\n\n if (regex.test(account)) {\n included = true;\n }\n }\n }\n\n if (hasIncludeFilter) {\n return included;\n }\n\n return true;\n }\n\n protected abstract initCloudClient(integrationConfig: Config): Promise<any>;\n\n // Get all cost allocation tag keys from one account\n protected async fetchTagKeys(\n _integrationConfig: Config,\n _client: any,\n _query: TagsQuery,\n ): Promise<{ tagKeys: string[]; provider: CLOUD_PROVIDER }> {\n // To be implemented by each provider client\n return { tagKeys: [], provider: this.provider };\n }\n\n // Get all tag values of the specified tag key from one account\n protected async fetchTagValues(\n _integrationConfig: Config,\n _client: any,\n _query: TagsQuery,\n _tagKey: string,\n ): Promise<{ tagValues: string[]; provider: CLOUD_PROVIDER }> {\n // To be implemented by each provider client\n return { tagValues: [], provider: this.provider };\n }\n\n protected abstract fetchCosts(integrationConfig: Config, client: any, query: CostQuery): Promise<any>;\n\n protected abstract transformCostsData(\n integrationConfig: Config,\n query: CostQuery,\n costResponse: any,\n ): Promise<Report[]>;\n\n protected logTransformationSummary(summary: TransformationSummary): void {\n logTransformationSummary(this.logger, this.provider, summary);\n }\n\n // Get aggregated unique tag keys across all accounts of this cloud provider\n async getTagKeys(query: TagsQuery): Promise<TagsResponse> {\n const integrationConfigs = this.config.getOptionalConfigArray(\n `backend.infraWallet.integrations.${this.provider.toLowerCase()}`,\n );\n if (!integrationConfigs) {\n return { tags: [], errors: [] };\n }\n\n const promises = [];\n const aggregatedTags: Tag[] = [];\n const errors: CloudProviderError[] = [];\n\n for (const integrationConfig of integrationConfigs) {\n const integrationName = integrationConfig.getString('name');\n\n const cachedTagKeys = await getTagKeysFromCache(this.cache, this.provider, integrationName, query);\n if (cachedTagKeys) {\n this.logger.info(`Reuse ${this.provider}/${integrationName} tag keys from cache`);\n\n for (const tag of cachedTagKeys) {\n if (!tagExists(aggregatedTags, tag)) {\n aggregatedTags.push(tag);\n }\n }\n\n continue;\n }\n\n const promise = (async () => {\n try {\n const client = await this.initCloudClient(integrationConfig);\n const response = await this.fetchTagKeys(integrationConfig, client, query);\n const tagKeysCache: Tag[] = [];\n\n for (const tagKey of response.tagKeys) {\n const tag = { key: tagKey, provider: response.provider };\n tagKeysCache.push(tag);\n\n if (!tagExists(aggregatedTags, tag)) {\n aggregatedTags.push(tag);\n }\n }\n await setTagKeysToCache(this.cache, tagKeysCache, this.provider, integrationName, query);\n } catch (e) {\n this.logger.error(e);\n errors.push({\n provider: this.provider,\n name: `${this.provider}/${integrationName}`,\n error: e.message,\n });\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n\n aggregatedTags.sort((a, b) => `${a.provider}/${a.key}`.localeCompare(`${b.provider}/${b.key}`));\n\n return {\n tags: aggregatedTags,\n errors: errors,\n };\n }\n\n // Get aggregated tag values of the specified tag key across all accounts of this cloud provider\n async getTagValues(query: TagsQuery, tagKey: string): Promise<TagsResponse> {\n const integrationConfigs = this.config.getOptionalConfigArray(\n `backend.infraWallet.integrations.${this.provider.toLowerCase()}`,\n );\n if (!integrationConfigs) {\n return { tags: [], errors: [] };\n }\n\n const promises = [];\n const aggregatedTags: Tag[] = [];\n const errors: CloudProviderError[] = [];\n\n for (const integrationConfig of integrationConfigs) {\n const integrationName = integrationConfig.getString('name');\n\n const cachedTagValues = await getTagValuesFromCache(this.cache, this.provider, integrationName, tagKey, query);\n if (cachedTagValues) {\n this.logger.info(`Reuse ${this.provider}/${integrationName}/${tagKey} tag values from cache`);\n\n for (const tag of cachedTagValues) {\n if (!tagExists(aggregatedTags, tag)) {\n aggregatedTags.push(tag);\n }\n }\n\n continue;\n }\n\n const promise = (async () => {\n try {\n const client = await this.initCloudClient(integrationConfig);\n const response = await this.fetchTagValues(integrationConfig, client, query, tagKey);\n const tagValuesCache: Tag[] = [];\n\n for (const tagValue of response.tagValues) {\n const tag = { key: tagKey, value: tagValue, provider: response.provider };\n tagValuesCache.push(tag);\n\n if (!tagExists(aggregatedTags, tag)) {\n aggregatedTags.push(tag);\n }\n }\n await setTagValuesToCache(this.cache, tagValuesCache, this.provider, integrationName, tagKey, query);\n } catch (e) {\n this.logger.error(e);\n errors.push({\n provider: this.provider,\n name: `${this.provider}/${integrationName}`,\n error: e.message,\n });\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n\n aggregatedTags.sort((a, b) =>\n `${a.provider}/${a.key}=${a.value}`.localeCompare(`${b.provider}/${b.key}=${b.value}`),\n );\n\n return {\n tags: aggregatedTags,\n errors: errors,\n };\n }\n\n async getCostReports(query: CostQuery): Promise<ClientResponse> {\n const autoloadCostData = this.config.getOptionalBoolean('backend.infraWallet.autoload.enabled') ?? false;\n const integrationConfigs = this.config.getOptionalConfigArray(\n `backend.infraWallet.integrations.${this.provider.toLowerCase()}`,\n );\n if (!integrationConfigs) {\n return { reports: [], errors: [] };\n }\n\n const results: Report[] = [];\n const errors: CloudProviderError[] = [];\n\n // if autoloadCostData enabled, for a query without any tags or groups, we get the results from the plugin database\n // skip Mock provider for autoloading data\n if (query.tags === '()' && query.groups === '' && autoloadCostData && this.provider !== CLOUD_PROVIDER.MOCK) {\n const reportsFromDatabase = await this.getCostReportsFromDatabase(query);\n reportsFromDatabase.forEach(report => {\n results.push(report);\n });\n } else {\n const promises = [];\n for (const integrationConfig of integrationConfigs) {\n const integrationName = integrationConfig.getString('name');\n\n // first check if there is any cached\n const cachedCosts = await getReportsFromCache(this.cache, this.provider, integrationName, query);\n if (cachedCosts) {\n this.logger.debug(`${this.provider}/${integrationName} costs from cache`);\n cachedCosts.forEach(cost => {\n results.push(cost);\n });\n continue;\n }\n\n const promise = (async () => {\n try {\n const client = await this.initCloudClient(integrationConfig);\n const costResponse = await this.fetchCosts(integrationConfig, client, query);\n\n const transformedReports = await this.transformCostsData(integrationConfig, query, costResponse);\n\n // cache the results\n await setReportsToCache(\n this.cache,\n transformedReports,\n this.provider,\n integrationName,\n query,\n getDefaultCacheTTL(CACHE_CATEGORY.COSTS, this.provider),\n );\n\n transformedReports.forEach((value: any) => {\n results.push(value);\n });\n } catch (e) {\n this.logger.error(e);\n errors.push({\n provider: this.provider,\n name: `${this.provider}/${integrationName}`,\n error: e.message,\n });\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n }\n\n return {\n reports: results,\n errors: errors,\n };\n }\n\n async saveCostReportsToDatabase(wallet: Wallet, granularity: GRANULARITY): Promise<void> {\n const count = await countCostItems(this.database, wallet.id, this.provider, granularity);\n\n const endTime = endOfMonth(new Date());\n let startTime = startOfMonth(addMonths(new Date(), -1));\n if (count === 0) {\n // if there is no record, the first call is going to fetch the last 364 days' cost data\n // it cannot be 365 day or 1 year because Azure API will responds with the following error\n // Invalid query definition: The time period for pulling the data cannot exceed 1 year(s)\n startTime = startOfMonth(\n addMonths(new Date(), -1 * NUMBER_OF_MONTHS_FETCHING_HISTORICAL_COSTS[this.provider] + 1),\n );\n }\n\n this.logger.debug(`Fetching ${granularity} costs from ${startTime} to ${endTime} for ${this.provider}`);\n\n const results: Report[] = [];\n const usageDateFormat = granularity === GRANULARITY.DAILY ? 'yyyyMMdd' : 'yyyyMM';\n try {\n const clientResponse = await this.getCostReports({\n filters: '',\n tags: '',\n groups: '',\n granularity: granularity,\n startTime: startTime.getTime().toString(),\n endTime: endTime.getTime().toString(),\n });\n clientResponse.reports.forEach((cost: Report) => {\n results.push(cost);\n });\n } catch (e) {\n this.logger.error(e);\n }\n\n await bulkInsertCostItems(\n this.database,\n wallet.id,\n this.provider,\n granularity,\n parseInt(format(startTime, usageDateFormat), 10),\n parseInt(format(endTime, usageDateFormat), 10),\n results,\n );\n }\n\n async getCostReportsFromDatabase(query: CostQuery): Promise<Report[]> {\n // TODO: support searching for different wallets in the future, for now it is always the default wallet\n const defaultWallet = await getWallet(this.database, 'default');\n if (defaultWallet !== undefined) {\n // query the database\n const usageDateFormat = query.granularity === 'daily' ? 'yyyyMMdd' : 'yyyyMM';\n const startUsageDate = parseInt(format(parseInt(query.startTime, 10), usageDateFormat), 10);\n const endUsageDate = parseInt(format(parseInt(query.endTime, 10), usageDateFormat), 10);\n const costItems = await getCostItems(\n this.database,\n defaultWallet.id,\n this.provider,\n query.granularity,\n startUsageDate,\n endUsageDate,\n );\n\n // transform the cost items into cost reports\n const transformedData = reduce(\n costItems,\n (accumulator: { [key: string]: Report }, row: CostItem) => {\n const key = row.key;\n const otherColumns =\n typeof row.other_columns === 'string' ? JSON.parse(row.other_columns) : row.other_columns;\n\n if (!accumulator[key]) {\n accumulator[key] = {\n id: key,\n account: row.account,\n service: row.service,\n category: row.category,\n provider: row.provider,\n providerType: PROVIDER_TYPE.INTEGRATION,\n reports: {},\n ...otherColumns,\n };\n }\n accumulator[key].reports[usageDateToPeriodString(row.usage_date)] = parseFloat(row.cost as string);\n\n return accumulator;\n },\n {},\n );\n\n return Object.values(transformedData);\n }\n\n return [];\n }\n}\n"],"names":["logTransformationSummary","getTagKeysFromCache","tagExists","setTagKeysToCache","getTagValuesFromCache","setTagValuesToCache","CLOUD_PROVIDER","getReportsFromCache","setReportsToCache","getDefaultCacheTTL","CACHE_CATEGORY","countCostItems","endOfMonth","startOfMonth","addMonths","NUMBER_OF_MONTHS_FETCHING_HISTORICAL_COSTS","GRANULARITY","bulkInsertCostItems","format","getWallet","getCostItems","reduce","PROVIDER_TYPE","usageDateToPeriodString"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InfraWalletClient.cjs.js","sources":["../../src/cost-clients/InfraWalletClient.ts"],"sourcesContent":["import { CacheService, DatabaseService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { addMonths, endOfMonth, format, startOfMonth } from 'date-fns';\nimport { reduce } from 'lodash';\nimport { getWallet } from '../controllers/MetricSettingController';\nimport { CostItem, bulkInsertCostItems, countCostItems, getCostItems } from '../models/CostItem';\nimport {\n CACHE_CATEGORY,\n CLOUD_PROVIDER,\n GRANULARITY,\n NUMBER_OF_MONTHS_FETCHING_HISTORICAL_COSTS,\n PROVIDER_TYPE,\n} from '../service/consts';\nimport {\n getDefaultCacheTTL,\n getReportsFromCache,\n getTagKeysFromCache,\n getTagValuesFromCache,\n logTransformationSummary,\n setReportsToCache,\n setTagKeysToCache,\n setTagValuesToCache,\n tagExists,\n usageDateToPeriodString,\n} from '../service/functions';\nimport {\n ClientResponse,\n CloudProviderError,\n CostQuery,\n Filter,\n Report,\n Tag,\n TagsQuery,\n TagsResponse,\n TransformationSummary,\n Wallet,\n} from '../service/types';\n\nexport abstract class InfraWalletClient {\n constructor(\n protected readonly provider: CLOUD_PROVIDER,\n protected readonly config: Config,\n protected readonly database: DatabaseService,\n protected readonly cache: CacheService,\n protected readonly logger: LoggerService,\n ) {}\n\n protected convertServiceName(serviceName: string): string {\n return `${this.provider}/${serviceName}`;\n }\n\n protected evaluateIntegrationFilters(account: string, integrationConfig: Config): boolean {\n const filters: Filter[] = [];\n for (const filter of integrationConfig.getOptionalConfigArray('filters') || []) {\n filters.push({\n type: filter.getString('type'),\n attribute: filter.getString('attribute'),\n pattern: filter.getString('pattern'),\n });\n }\n return this.evaluateFilters(account, filters);\n }\n\n private evaluateFilters(account: string, filters: Filter[]): boolean {\n if (!filters || filters.length === 0) {\n // include if no filter\n return true;\n }\n\n let included = false;\n let hasIncludeFilter = false;\n\n for (const filter of filters) {\n const regex = new RegExp(filter.pattern);\n\n if (filter.type === 'exclude' && regex.test(account)) {\n // exclude immediately if an exclude filter matches\n return false;\n }\n\n if (filter.type === 'include') {\n hasIncludeFilter = true;\n\n if (regex.test(account)) {\n included = true;\n }\n }\n }\n\n if (hasIncludeFilter) {\n return included;\n }\n\n return true;\n }\n\n protected abstract initCloudClient(integrationConfig: Config): Promise<any>;\n\n // Get all cost allocation tag keys from one account\n protected async fetchTagKeys(\n _integrationConfig: Config,\n _client: any,\n _query: TagsQuery,\n ): Promise<{ tagKeys: string[]; provider: CLOUD_PROVIDER }> {\n // To be implemented by each provider client\n return { tagKeys: [], provider: this.provider };\n }\n\n // Get all tag values of the specified tag key from one account\n protected async fetchTagValues(\n _integrationConfig: Config,\n _client: any,\n _query: TagsQuery,\n _tagKey: string,\n ): Promise<{ tagValues: string[]; provider: CLOUD_PROVIDER }> {\n // To be implemented by each provider client\n return { tagValues: [], provider: this.provider };\n }\n\n protected abstract fetchCosts(integrationConfig: Config, client: any, query: CostQuery): Promise<any>;\n protected async fetchForecast(_integrationConfig: Config): Promise<number | null> {\n return null;\n }\n\n protected abstract transformCostsData(\n integrationConfig: Config,\n query: CostQuery,\n costResponse: any,\n ): Promise<Report[]>;\n\n protected logTransformationSummary(summary: TransformationSummary): void {\n logTransformationSummary(this.logger, this.provider, summary);\n }\n\n // Get aggregated unique tag keys across all accounts of this cloud provider\n async getTagKeys(query: TagsQuery): Promise<TagsResponse> {\n const integrationConfigs = this.config.getOptionalConfigArray(\n `backend.infraWallet.integrations.${this.provider.toLowerCase()}`,\n );\n if (!integrationConfigs) {\n return { tags: [], errors: [] };\n }\n\n const promises = [];\n const aggregatedTags: Tag[] = [];\n const errors: CloudProviderError[] = [];\n\n for (const integrationConfig of integrationConfigs) {\n const integrationName = integrationConfig.getString('name');\n\n const cachedTagKeys = await getTagKeysFromCache(this.cache, this.provider, integrationName, query);\n if (cachedTagKeys) {\n this.logger.info(`Reuse ${this.provider}/${integrationName} tag keys from cache`);\n\n for (const tag of cachedTagKeys) {\n if (!tagExists(aggregatedTags, tag)) {\n aggregatedTags.push(tag);\n }\n }\n\n continue;\n }\n\n const promise = (async () => {\n try {\n const client = await this.initCloudClient(integrationConfig);\n const response = await this.fetchTagKeys(integrationConfig, client, query);\n const tagKeysCache: Tag[] = [];\n\n for (const tagKey of response.tagKeys) {\n const tag = { key: tagKey, provider: response.provider };\n tagKeysCache.push(tag);\n\n if (!tagExists(aggregatedTags, tag)) {\n aggregatedTags.push(tag);\n }\n }\n await setTagKeysToCache(this.cache, tagKeysCache, this.provider, integrationName, query);\n } catch (e) {\n this.logger.error(e);\n errors.push({\n provider: this.provider,\n name: `${this.provider}/${integrationName}`,\n error: e.message,\n });\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n\n aggregatedTags.sort((a, b) => `${a.provider}/${a.key}`.localeCompare(`${b.provider}/${b.key}`));\n\n return {\n tags: aggregatedTags,\n errors: errors,\n };\n }\n\n // Get aggregated tag values of the specified tag key across all accounts of this cloud provider\n async getTagValues(query: TagsQuery, tagKey: string): Promise<TagsResponse> {\n const integrationConfigs = this.config.getOptionalConfigArray(\n `backend.infraWallet.integrations.${this.provider.toLowerCase()}`,\n );\n if (!integrationConfigs) {\n return { tags: [], errors: [] };\n }\n\n const promises = [];\n const aggregatedTags: Tag[] = [];\n const errors: CloudProviderError[] = [];\n\n for (const integrationConfig of integrationConfigs) {\n const integrationName = integrationConfig.getString('name');\n\n const cachedTagValues = await getTagValuesFromCache(this.cache, this.provider, integrationName, tagKey, query);\n if (cachedTagValues) {\n this.logger.info(`Reuse ${this.provider}/${integrationName}/${tagKey} tag values from cache`);\n\n for (const tag of cachedTagValues) {\n if (!tagExists(aggregatedTags, tag)) {\n aggregatedTags.push(tag);\n }\n }\n\n continue;\n }\n\n const promise = (async () => {\n try {\n const client = await this.initCloudClient(integrationConfig);\n const response = await this.fetchTagValues(integrationConfig, client, query, tagKey);\n const tagValuesCache: Tag[] = [];\n\n for (const tagValue of response.tagValues) {\n const tag = { key: tagKey, value: tagValue, provider: response.provider };\n tagValuesCache.push(tag);\n\n if (!tagExists(aggregatedTags, tag)) {\n aggregatedTags.push(tag);\n }\n }\n await setTagValuesToCache(this.cache, tagValuesCache, this.provider, integrationName, tagKey, query);\n } catch (e) {\n this.logger.error(e);\n errors.push({\n provider: this.provider,\n name: `${this.provider}/${integrationName}`,\n error: e.message,\n });\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n\n aggregatedTags.sort((a, b) =>\n `${a.provider}/${a.key}=${a.value}`.localeCompare(`${b.provider}/${b.key}=${b.value}`),\n );\n\n return {\n tags: aggregatedTags,\n errors: errors,\n };\n }\n\n async getCostReports(query: CostQuery): Promise<ClientResponse> {\n const autoloadCostData = this.config.getOptionalBoolean('backend.infraWallet.autoload.enabled') ?? false;\n const integrationConfigs = this.config.getOptionalConfigArray(\n `backend.infraWallet.integrations.${this.provider.toLowerCase()}`,\n );\n if (!integrationConfigs) {\n return { reports: [], errors: [] };\n }\n\n const results: Report[] = [];\n const forecasts: Record<string, number> = {};\n const errors: CloudProviderError[] = [];\n\n const now = new Date();\n const isCurrentMonthIncluded =\n query.granularity === GRANULARITY.MONTHLY &&\n parseInt(query.endTime, 10) >= new Date(now.getFullYear(), now.getMonth(), 1).getTime();\n\n // if autoloadCostData enabled, for a query without any tags or groups, we get the results from the plugin database\n // skip Mock provider for autoloading data\n if (query.tags === '()' && query.groups === '' && autoloadCostData && this.provider !== CLOUD_PROVIDER.MOCK) {\n const reportsFromDatabase = await this.getCostReportsFromDatabase(query);\n reportsFromDatabase.forEach(report => {\n results.push(report);\n });\n } else {\n const promises = [];\n for (const integrationConfig of integrationConfigs) {\n const integrationName = integrationConfig.getString('name');\n\n // first check if there is any cached\n const cachedCosts = await getReportsFromCache(this.cache, this.provider, integrationName, query);\n if (cachedCosts) {\n this.logger.debug(`${this.provider}/${integrationName} costs from cache`);\n cachedCosts.forEach(cost => {\n results.push(cost);\n });\n continue;\n }\n\n const promise = (async () => {\n try {\n const client = await this.initCloudClient(integrationConfig);\n const costResponse = await this.fetchCosts(integrationConfig, client, query);\n\n const transformedReports = await this.transformCostsData(integrationConfig, query, costResponse);\n\n // cache the results\n await setReportsToCache(\n this.cache,\n transformedReports,\n this.provider,\n integrationName,\n query,\n getDefaultCacheTTL(CACHE_CATEGORY.COSTS, this.provider),\n );\n\n transformedReports.forEach((value: any) => {\n results.push(value);\n });\n if (isCurrentMonthIncluded) {\n const integrationForecast = await this.fetchForecast(integrationConfig);\n if (integrationForecast !== null) {\n forecasts[this.provider] = integrationForecast;\n }\n }\n } catch (e) {\n this.logger.error(e);\n errors.push({\n provider: this.provider,\n name: `${this.provider}/${integrationName}`,\n error: e.message,\n });\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n }\n\n return {\n reports: results,\n forecasts: forecasts,\n errors: errors,\n };\n }\n\n async saveCostReportsToDatabase(wallet: Wallet, granularity: GRANULARITY): Promise<void> {\n const count = await countCostItems(this.database, wallet.id, this.provider, granularity);\n\n const endTime = endOfMonth(new Date());\n let startTime = startOfMonth(addMonths(new Date(), -1));\n if (count === 0) {\n // if there is no record, the first call is going to fetch the last 364 days' cost data\n // it cannot be 365 day or 1 year because Azure API will responds with the following error\n // Invalid query definition: The time period for pulling the data cannot exceed 1 year(s)\n startTime = startOfMonth(\n addMonths(new Date(), -1 * NUMBER_OF_MONTHS_FETCHING_HISTORICAL_COSTS[this.provider] + 1),\n );\n }\n\n this.logger.debug(`Fetching ${granularity} costs from ${startTime} to ${endTime} for ${this.provider}`);\n\n const results: Report[] = [];\n const usageDateFormat = granularity === GRANULARITY.DAILY ? 'yyyyMMdd' : 'yyyyMM';\n try {\n const clientResponse = await this.getCostReports({\n filters: '',\n tags: '',\n groups: '',\n granularity: granularity,\n startTime: startTime.getTime().toString(),\n endTime: endTime.getTime().toString(),\n });\n clientResponse.reports.forEach((cost: Report) => {\n results.push(cost);\n });\n } catch (e) {\n this.logger.error(e);\n }\n\n await bulkInsertCostItems(\n this.database,\n wallet.id,\n this.provider,\n granularity,\n parseInt(format(startTime, usageDateFormat), 10),\n parseInt(format(endTime, usageDateFormat), 10),\n results,\n );\n }\n\n async getCostReportsFromDatabase(query: CostQuery): Promise<Report[]> {\n // TODO: support searching for different wallets in the future, for now it is always the default wallet\n const defaultWallet = await getWallet(this.database, 'default');\n if (defaultWallet !== undefined) {\n // query the database\n const usageDateFormat = query.granularity === 'daily' ? 'yyyyMMdd' : 'yyyyMM';\n const startUsageDate = parseInt(format(parseInt(query.startTime, 10), usageDateFormat), 10);\n const endUsageDate = parseInt(format(parseInt(query.endTime, 10), usageDateFormat), 10);\n const costItems = await getCostItems(\n this.database,\n defaultWallet.id,\n this.provider,\n query.granularity,\n startUsageDate,\n endUsageDate,\n );\n\n // transform the cost items into cost reports\n const transformedData = reduce(\n costItems,\n (accumulator: { [key: string]: Report }, row: CostItem) => {\n const key = row.key;\n const otherColumns =\n typeof row.other_columns === 'string' ? JSON.parse(row.other_columns) : row.other_columns;\n\n if (!accumulator[key]) {\n accumulator[key] = {\n id: key,\n account: row.account,\n service: row.service,\n category: row.category,\n provider: row.provider,\n providerType: PROVIDER_TYPE.INTEGRATION,\n reports: {},\n ...otherColumns,\n };\n }\n accumulator[key].reports[usageDateToPeriodString(row.usage_date)] = parseFloat(row.cost as string);\n\n return accumulator;\n },\n {},\n );\n\n return Object.values(transformedData);\n }\n\n return [];\n }\n}\n"],"names":["logTransformationSummary","getTagKeysFromCache","tagExists","setTagKeysToCache","getTagValuesFromCache","setTagValuesToCache","GRANULARITY","CLOUD_PROVIDER","getReportsFromCache","setReportsToCache","getDefaultCacheTTL","CACHE_CATEGORY","countCostItems","endOfMonth","startOfMonth","addMonths","NUMBER_OF_MONTHS_FETCHING_HISTORICAL_COSTS","bulkInsertCostItems","format","getWallet","getCostItems","reduce","PROVIDER_TYPE","usageDateToPeriodString"],"mappings":"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"}
|
|
@@ -33,6 +33,7 @@ async function getReports(queryParameters, config, database, cache, logger) {
|
|
|
33
33
|
const { filters, tags, groups, granularityString, startTime, endTime } = queryParameters;
|
|
34
34
|
const promises = [];
|
|
35
35
|
const results = [];
|
|
36
|
+
let forecasts = {};
|
|
36
37
|
const errors = [];
|
|
37
38
|
const granularity = Object.values(consts.GRANULARITY).includes(granularityString) ? granularityString : consts.GRANULARITY.MONTHLY;
|
|
38
39
|
const providerTags = {};
|
|
@@ -65,6 +66,9 @@ async function getReports(queryParameters, config, database, cache, logger) {
|
|
|
65
66
|
clientResponse.reports.forEach((cost) => {
|
|
66
67
|
results.push(cost);
|
|
67
68
|
});
|
|
69
|
+
if (clientResponse.forecasts) {
|
|
70
|
+
forecasts = { ...forecasts, ...clientResponse.forecasts };
|
|
71
|
+
}
|
|
68
72
|
} catch (e) {
|
|
69
73
|
logger.error(e);
|
|
70
74
|
errors.push({
|
|
@@ -88,7 +92,7 @@ async function getReports(queryParameters, config, database, cache, logger) {
|
|
|
88
92
|
return values.includes(reportValue);
|
|
89
93
|
});
|
|
90
94
|
});
|
|
91
|
-
return { reports: filteredResults, clientErrors: errors };
|
|
95
|
+
return { reports: filteredResults, clientErrors: errors, forecasts };
|
|
92
96
|
}
|
|
93
97
|
async function createRouter(options) {
|
|
94
98
|
const { logger, config, scheduler, cache, database, additionalFilters } = options;
|
|
@@ -163,11 +167,11 @@ async function createRouter(options) {
|
|
|
163
167
|
reportFilters = await filter.augmentFilters(reportFilters);
|
|
164
168
|
}
|
|
165
169
|
}
|
|
166
|
-
const { reports, clientErrors } = await getReports(reportFilters, config, database, cache, logger);
|
|
170
|
+
const { reports, forecasts, clientErrors } = await getReports(reportFilters, config, database, cache, logger);
|
|
167
171
|
if (clientErrors.length > 0) {
|
|
168
172
|
response.status(207).json({ data: reports, errors: clientErrors, status: 207 });
|
|
169
173
|
} else {
|
|
170
|
-
response.json({ data: reports, errors: clientErrors, status: 200 });
|
|
174
|
+
response.json({ data: reports, forecasts, errors: clientErrors, status: 200 });
|
|
171
175
|
}
|
|
172
176
|
});
|
|
173
177
|
router.get("/tag-keys", async (request, response) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport { CacheService, DatabaseService, LoggerService, resolvePackagePath } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport {\n deleteWalletMetricSetting,\n getWallet,\n getWalletMetricSettings,\n updateOrInsertWalletMetricSetting,\n} from '../controllers/MetricSettingController';\nimport { InfraWalletClient } from '../cost-clients/InfraWalletClient';\nimport { MetricProvider } from '../metric-providers/MetricProvider';\nimport { Budget, getBudget, getBudgets, upsertBudget } from '../models/Budget';\nimport { deleteCostItems } from '../models/CostItem';\nimport {\n CustomCost,\n createCustomCosts,\n deleteCustomCost,\n getCustomCosts,\n updateOrInsertCustomCost,\n} from '../models/CustomCost';\nimport { fetchAndSaveCosts } from '../tasks/fetchAndSaveCosts';\nimport { CategoryMappingService } from './CategoryMappingService';\nimport { COST_CLIENT_MAPPINGS, GRANULARITY, METRIC_PROVIDER_MAPPINGS } from './consts';\nimport { parseFilters, parseTags, tagsToString } from './functions';\nimport { CloudProviderError, Metric, MetricSetting, Report, ReportParameters, RouterOptions, Tag } from './types';\n\nasync function setUpDatabase(database: DatabaseService) {\n // check database migrations\n const client = await database.getClient();\n const migrationsDir = resolvePackagePath('@electrolux-oss/plugin-infrawallet-backend', 'migrations');\n if (!database.migrations?.skip) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n // insert default category_mappings to the database\n const seedsDir = resolvePackagePath('@electrolux-oss/plugin-infrawallet-backend', 'seeds');\n await client.seed.run({ directory: seedsDir });\n}\n\nasync function getReports(\n queryParameters: ReportParameters,\n config: Config,\n database: DatabaseService,\n cache: CacheService,\n logger: LoggerService,\n): Promise<{ reports: Report[]; clientErrors: CloudProviderError[] }> {\n const { filters, tags, groups, granularityString, startTime, endTime } = queryParameters;\n const promises: Promise<void>[] = [];\n const results: Report[] = [];\n const errors: CloudProviderError[] = [];\n\n const granularity: GRANULARITY = Object.values(GRANULARITY).includes(granularityString as GRANULARITY)\n ? (granularityString as GRANULARITY)\n : GRANULARITY.MONTHLY;\n\n // group tags by providers\n const providerTags: Record<string, Tag[]> = {};\n for (const tag of tags) {\n const provider = tag.provider.toLowerCase();\n if (!providerTags[provider]) {\n providerTags[provider] = [];\n }\n\n providerTags[provider].push(tag);\n }\n\n const categoryMappingService = CategoryMappingService.getInstance();\n await categoryMappingService.refreshCategoryMappings();\n\n const conf = config.getConfig('backend.infraWallet.integrations');\n conf\n .keys()\n .concat(['custom'])\n .forEach((provider: string) => {\n if (provider in COST_CLIENT_MAPPINGS) {\n const client: InfraWalletClient = COST_CLIENT_MAPPINGS[provider].create(config, database, cache, logger);\n const fetchCloudCosts = (async () => {\n try {\n const clientResponse = await client.getCostReports({\n filters: filters,\n tags: tagsToString(providerTags[provider.toLowerCase()]),\n groups: groups,\n granularity: granularity,\n startTime: startTime,\n endTime: endTime,\n });\n clientResponse.errors.forEach((e: CloudProviderError) => {\n errors.push(e);\n });\n clientResponse.reports.forEach((cost: Report) => {\n results.push(cost);\n });\n } catch (e) {\n logger.error(e);\n errors.push({\n provider: client.constructor.name,\n name: client.constructor.name,\n error: e.message,\n });\n }\n })();\n promises.push(fetchCloudCosts);\n }\n });\n\n await Promise.all(promises);\n\n const parsedFilters = parseFilters(filters);\n\n const filteredResults = results.filter(report => {\n return Object.entries(parsedFilters).every(([key, values]) => {\n const reportValue = report[key];\n if (typeof reportValue !== 'string') {\n return false;\n }\n return values.includes(reportValue);\n });\n });\n\n return { reports: filteredResults, clientErrors: errors };\n}\n\nexport async function createRouter(options: RouterOptions): Promise<express.Router> {\n const { logger, config, scheduler, cache, database, additionalFilters } = options;\n // do database migrations here to support the legacy backend system\n await setUpDatabase(database);\n\n // init CategoryMappingService\n CategoryMappingService.initInstance(cache, logger);\n\n const router = Router();\n router.use(express.json());\n\n router.get('/health', (_, response) => {\n logger.info('PONG!');\n response.json({ status: 'ok' });\n });\n\n // Endpoint to trigger the fetchAndSaveCosts task manually\n router.get('/fetch_and_save_costs', async (_, response) => {\n try {\n // Trigger the scheduled task using the scheduler\n await scheduler.triggerTask('infrawallet-autoload-costs');\n\n response.json({\n status: 'ok',\n message: 'Cost data fetching task has been triggered. Check logs for execution details.',\n });\n } catch (error) {\n logger.error(`Error triggering cost data fetch task: ${error.message}`, { error });\n\n // Fall back to direct execution if task triggering fails\n try {\n logger.info('Falling back to direct execution of fetch and save costs');\n await fetchAndSaveCosts(options);\n response.json({\n status: 'ok',\n message: 'Cost data fetch completed successfully via direct execution.',\n });\n } catch (directError) {\n logger.error(`Direct cost data fetch failed: ${directError.message}`, { error: directError });\n response.status(500).json({\n status: 'error',\n message: 'Failed to fetch cost data. Check logs for more details.',\n });\n }\n }\n });\n\n router.post('/:walletName/delete_cost_items', async (request, response) => {\n const walletName = request.params.walletName;\n const granularity = request.body.granularity as string;\n const provider = request.body.provider as string;\n\n const wallet = await getWallet(database, walletName);\n if (wallet && granularity && provider) {\n const rowsDeleted = await deleteCostItems(database, wallet.id, provider, granularity);\n response.json({\n message: `Deleted ${rowsDeleted} ${granularity} ${provider} cost records in ${walletName}`,\n status: 'ok',\n });\n } else {\n response.status(404).json({ error: 'Wallet not found or missing parameters', status: 404 });\n }\n });\n\n router.get('/reports', async (request, response) => {\n const filters = request.query.filters as string;\n const tags = parseTags(request.query.tags as string);\n const groups = request.query.groups as string;\n const granularityString = request.query.granularity as string;\n const startTime = request.query.startTime as string;\n const endTime = request.query.endTime as string;\n const [entityNamespace, entityName] = decodeURI(request.query.entityName as string)?.split('/') || [];\n\n let reportFilters: ReportParameters = {\n filters,\n tags,\n groups,\n granularityString,\n startTime,\n endTime,\n entityNamespace,\n entityName,\n };\n if (additionalFilters.length > 0) {\n for (const filter of additionalFilters) {\n reportFilters = await filter.augmentFilters(reportFilters);\n }\n }\n\n const { reports, clientErrors } = await getReports(reportFilters, config, database, cache, logger);\n\n if (clientErrors.length > 0) {\n response.status(207).json({ data: reports, errors: clientErrors, status: 207 });\n } else {\n response.json({ data: reports, errors: clientErrors, status: 200 });\n }\n });\n\n router.get('/tag-keys', async (request, response) => {\n const tags: Tag[] = [];\n const errors: CloudProviderError[] = [];\n\n const tagProvider = request.query.provider as string;\n const startTime = request.query.startTime as string;\n const endTime = request.query.endTime as string;\n const promises: Promise<void>[] = [];\n\n const conf = config.getConfig('backend.infraWallet.integrations');\n conf.keys().forEach((provider: string) => {\n if (provider.toLowerCase() === tagProvider.toLowerCase() && provider in COST_CLIENT_MAPPINGS) {\n const client: InfraWalletClient = COST_CLIENT_MAPPINGS[provider].create(config, database, cache, logger);\n const getTagKeys = (async () => {\n try {\n const clientResponse = await client.getTagKeys({\n startTime: startTime,\n endTime: endTime,\n });\n clientResponse.errors.forEach((e: CloudProviderError) => {\n errors.push(e);\n });\n clientResponse.tags.forEach((tag: Tag) => {\n tags.push(tag);\n });\n } catch (e) {\n logger.error(e);\n errors.push({\n provider: client.constructor.name,\n name: client.constructor.name,\n error: e.message,\n });\n }\n })();\n promises.push(getTagKeys);\n }\n });\n\n await Promise.all(promises);\n\n if (errors.length > 0) {\n response.status(207).json({ data: tags, errors: errors, status: 207 });\n } else {\n response.json({ data: tags, errors: errors, status: 200 });\n }\n });\n\n router.get('/tag-values', async (request, response) => {\n const tags: Tag[] = [];\n const errors: CloudProviderError[] = [];\n\n const startTime = request.query.startTime as string;\n const endTime = request.query.endTime as string;\n const tagKey = request.query.tag as string;\n const tagProvider = request.query.provider as string;\n const promises: Promise<void>[] = [];\n\n const conf = config.getConfig('backend.infraWallet.integrations');\n conf.keys().forEach((provider: string) => {\n if (provider in COST_CLIENT_MAPPINGS && provider.toLowerCase() === tagProvider.toLowerCase()) {\n const client: InfraWalletClient = COST_CLIENT_MAPPINGS[provider].create(config, database, cache, logger);\n const getTagValues = (async () => {\n try {\n const clientResponse = await client.getTagValues(\n {\n startTime: startTime,\n endTime: endTime,\n },\n tagKey,\n );\n clientResponse.errors.forEach((e: CloudProviderError) => {\n errors.push(e);\n });\n clientResponse.tags.forEach((tag: Tag) => {\n tags.push(tag);\n });\n } catch (e) {\n logger.error(e);\n errors.push({\n provider: client.constructor.name,\n name: client.constructor.name,\n error: e.message,\n });\n }\n })();\n promises.push(getTagValues);\n }\n });\n\n await Promise.all(promises);\n\n if (errors.length > 0) {\n response.status(207).json({ data: tags, errors: errors, status: 207 });\n } else {\n response.json({ data: tags, errors: errors, status: 200 });\n }\n });\n\n router.get('/:walletName/budgets', async (request, response) => {\n const walletName = request.params.walletName;\n const provider = request.query.provider as string;\n let budgets;\n\n if (provider) {\n budgets = await getBudget(database, walletName, provider);\n } else {\n budgets = await getBudgets(database, walletName);\n }\n\n response.json({ data: budgets, status: 200 });\n });\n\n router.put('/:walletName/budgets', async (request, response) => {\n const walletName = request.params.walletName;\n const result = await upsertBudget(database, walletName, request.body as Budget);\n response.json({ updated: result, status: 200 });\n });\n\n router.get('/custom-costs', async (_request, response) => {\n const customCosts = await getCustomCosts(database);\n\n // make it compatible with the SQLite database\n for (const cost of customCosts) {\n if (typeof cost.tags === 'string') {\n try {\n cost.tags = JSON.parse(cost.tags);\n } catch (error) {\n cost.tags = {};\n }\n }\n }\n\n response.json({ data: customCosts, status: 200 });\n });\n\n router.post('/custom-costs', async (request, response) => {\n const readOnly = config.getOptionalBoolean('infraWallet.settings.readOnly') ?? false;\n\n if (readOnly) {\n response.status(403).json({ error: 'API not enabled in read-only mode', status: 403 });\n return;\n }\n\n const updatedCustomCost = await createCustomCosts(database, request.body as CustomCost[]);\n response.json({ created: updatedCustomCost, status: 200 });\n });\n\n router.put('/custom-cost', async (request, response) => {\n const readOnly = config.getOptionalBoolean('infraWallet.settings.readOnly') ?? false;\n\n if (readOnly) {\n response.status(403).json({ error: 'API not enabled in read-only mode', status: 403 });\n return;\n }\n\n const updatedCustomCost = await updateOrInsertCustomCost(database, request.body as CustomCost);\n response.json({ updated: updatedCustomCost, status: 200 });\n });\n\n router.delete('/custom-cost', async (request, response) => {\n const readOnly = config.getOptionalBoolean('infraWallet.settings.readOnly') ?? false;\n\n if (readOnly) {\n response.status(403).json({ error: 'API not enabled in read-only mode', status: 403 });\n return;\n }\n\n const deletedCustomCost = await deleteCustomCost(database, request.body as CustomCost);\n response.json({ deleted: deletedCustomCost, status: 200 });\n });\n\n router.get('/:walletName/metrics', async (request, response) => {\n const walletName = request.params.walletName;\n const granularity = request.query.granularity as string;\n const startTime = request.query.startTime as string;\n const endTime = request.query.endTime as string;\n const promises: Promise<void>[] = [];\n const results: Metric[] = [];\n const errors: CloudProviderError[] = [];\n\n const conf = config.getConfig('backend.infraWallet.metricProviders');\n conf.keys().forEach((provider: string) => {\n if (provider in METRIC_PROVIDER_MAPPINGS) {\n const client: MetricProvider = METRIC_PROVIDER_MAPPINGS[provider].create(config, database, cache, logger);\n const fetchMetrics = (async () => {\n try {\n const metricResponse = await client.getMetrics({\n walletName: walletName,\n granularity: granularity,\n startTime: startTime,\n endTime: endTime,\n });\n metricResponse.errors.forEach((e: CloudProviderError) => {\n errors.push(e);\n });\n metricResponse.metrics.forEach((metric: Metric) => {\n results.push(metric);\n });\n } catch (e) {\n logger.error(e);\n errors.push({\n provider: client.constructor.name,\n name: client.constructor.name,\n error: e.message,\n });\n }\n })();\n promises.push(fetchMetrics);\n }\n });\n\n await Promise.all(promises);\n\n if (errors.length > 0) {\n response.status(207).json({ data: results, errors: errors, status: 207 });\n } else {\n response.json({ data: results, errors: errors, status: 200 });\n }\n });\n\n router.get('/:walletName', async (request, response) => {\n const walletName = request.params.walletName;\n const wallet = await getWallet(database, walletName);\n if (wallet === undefined) {\n response.status(404).json({ error: 'Wallet not found', status: 404 });\n return;\n }\n\n response.json({ data: wallet, status: 200 });\n });\n\n router.get('/:walletName/metrics-setting', async (request, response) => {\n const walletName = request.params.walletName;\n const metricSettings = await getWalletMetricSettings(database, walletName);\n response.json({ data: metricSettings, status: 200 });\n });\n\n router.get('/metric/metric-configs', async (_request, response) => {\n const conf = config.getConfig('backend.infraWallet.metricProviders');\n const configNames: { metric_provider: string; config_name: string }[] = [];\n conf.keys().forEach((provider: string) => {\n const configs = conf.getOptionalConfigArray(provider);\n if (configs) {\n configs.forEach(c => {\n configNames.push({ metric_provider: provider, config_name: c.getString('name') });\n });\n }\n });\n\n response.json({ data: configNames, status: 200 });\n });\n\n router.put('/:walletName/metrics-setting', async (request, response) => {\n const readOnly = config.getOptionalBoolean('infraWallet.settings.readOnly') ?? false;\n\n if (readOnly) {\n response.status(403).json({ error: 'API not enabled in read-only mode', status: 403 });\n return;\n }\n\n const updatedMetricSetting = await updateOrInsertWalletMetricSetting(database, request.body as MetricSetting);\n response.json({ updated: updatedMetricSetting, status: 200 });\n });\n\n router.delete('/:walletName/metrics-setting', async (request, response) => {\n const readOnly = config.getOptionalBoolean('infraWallet.settings.readOnly') ?? false;\n\n if (readOnly) {\n response.status(403).json({ error: 'API not enabled in read-only mode', status: 403 });\n return;\n }\n\n const deletedMetricSetting = await deleteWalletMetricSetting(database, request.body as MetricSetting);\n response.json({ deleted: deletedMetricSetting, status: 200 });\n });\n\n const middleware = MiddlewareFactory.create({ config, logger });\n router.use(middleware.error());\n\n return router;\n}\n"],"names":["resolvePackagePath","GRANULARITY","CategoryMappingService","COST_CLIENT_MAPPINGS","tagsToString","parseFilters","Router","express","fetchAndSaveCosts","getWallet","deleteCostItems","parseTags","getBudget","getBudgets","upsertBudget","getCustomCosts","createCustomCosts","updateOrInsertCustomCost","deleteCustomCost","METRIC_PROVIDER_MAPPINGS","getWalletMetricSettings","updateOrInsertWalletMetricSetting","deleteWalletMetricSetting","MiddlewareFactory"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport { CacheService, DatabaseService, LoggerService, resolvePackagePath } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport {\n deleteWalletMetricSetting,\n getWallet,\n getWalletMetricSettings,\n updateOrInsertWalletMetricSetting,\n} from '../controllers/MetricSettingController';\nimport { InfraWalletClient } from '../cost-clients/InfraWalletClient';\nimport { MetricProvider } from '../metric-providers/MetricProvider';\nimport { Budget, getBudget, getBudgets, upsertBudget } from '../models/Budget';\nimport { deleteCostItems } from '../models/CostItem';\nimport {\n CustomCost,\n createCustomCosts,\n deleteCustomCost,\n getCustomCosts,\n updateOrInsertCustomCost,\n} from '../models/CustomCost';\nimport { fetchAndSaveCosts } from '../tasks/fetchAndSaveCosts';\nimport { CategoryMappingService } from './CategoryMappingService';\nimport { COST_CLIENT_MAPPINGS, GRANULARITY, METRIC_PROVIDER_MAPPINGS } from './consts';\nimport { parseFilters, parseTags, tagsToString } from './functions';\nimport { CloudProviderError, Metric, MetricSetting, Report, ReportParameters, RouterOptions, Tag } from './types';\n\nasync function setUpDatabase(database: DatabaseService) {\n // check database migrations\n const client = await database.getClient();\n const migrationsDir = resolvePackagePath('@electrolux-oss/plugin-infrawallet-backend', 'migrations');\n if (!database.migrations?.skip) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n // insert default category_mappings to the database\n const seedsDir = resolvePackagePath('@electrolux-oss/plugin-infrawallet-backend', 'seeds');\n await client.seed.run({ directory: seedsDir });\n}\n\nasync function getReports(\n queryParameters: ReportParameters,\n config: Config,\n database: DatabaseService,\n cache: CacheService,\n logger: LoggerService,\n): Promise<{ reports: Report[]; forecasts: Record<string, number>; clientErrors: CloudProviderError[] }> {\n const { filters, tags, groups, granularityString, startTime, endTime } = queryParameters;\n const promises: Promise<void>[] = [];\n const results: Report[] = [];\n let forecasts: Record<string, number> = {};\n const errors: CloudProviderError[] = [];\n\n const granularity: GRANULARITY = Object.values(GRANULARITY).includes(granularityString as GRANULARITY)\n ? (granularityString as GRANULARITY)\n : GRANULARITY.MONTHLY;\n\n // group tags by providers\n const providerTags: Record<string, Tag[]> = {};\n for (const tag of tags) {\n const provider = tag.provider.toLowerCase();\n if (!providerTags[provider]) {\n providerTags[provider] = [];\n }\n\n providerTags[provider].push(tag);\n }\n\n const categoryMappingService = CategoryMappingService.getInstance();\n await categoryMappingService.refreshCategoryMappings();\n\n const conf = config.getConfig('backend.infraWallet.integrations');\n conf\n .keys()\n .concat(['custom'])\n .forEach((provider: string) => {\n if (provider in COST_CLIENT_MAPPINGS) {\n const client: InfraWalletClient = COST_CLIENT_MAPPINGS[provider].create(config, database, cache, logger);\n const fetchCloudCosts = (async () => {\n try {\n const clientResponse = await client.getCostReports({\n filters: filters,\n tags: tagsToString(providerTags[provider.toLowerCase()]),\n groups: groups,\n granularity: granularity,\n startTime: startTime,\n endTime: endTime,\n });\n clientResponse.errors.forEach((e: CloudProviderError) => {\n errors.push(e);\n });\n clientResponse.reports.forEach((cost: Report) => {\n results.push(cost);\n });\n if (clientResponse.forecasts) {\n forecasts = { ...forecasts, ...clientResponse.forecasts };\n }\n } catch (e) {\n logger.error(e);\n errors.push({\n provider: client.constructor.name,\n name: client.constructor.name,\n error: e.message,\n });\n }\n })();\n promises.push(fetchCloudCosts);\n }\n });\n\n await Promise.all(promises);\n\n const parsedFilters = parseFilters(filters);\n\n const filteredResults = results.filter(report => {\n return Object.entries(parsedFilters).every(([key, values]) => {\n const reportValue = report[key];\n if (typeof reportValue !== 'string') {\n return false;\n }\n return values.includes(reportValue);\n });\n });\n\n return { reports: filteredResults, clientErrors: errors, forecasts: forecasts };\n}\n\nexport async function createRouter(options: RouterOptions): Promise<express.Router> {\n const { logger, config, scheduler, cache, database, additionalFilters } = options;\n // do database migrations here to support the legacy backend system\n await setUpDatabase(database);\n\n // init CategoryMappingService\n CategoryMappingService.initInstance(cache, logger);\n\n const router = Router();\n router.use(express.json());\n\n router.get('/health', (_, response) => {\n logger.info('PONG!');\n response.json({ status: 'ok' });\n });\n\n // Endpoint to trigger the fetchAndSaveCosts task manually\n router.get('/fetch_and_save_costs', async (_, response) => {\n try {\n // Trigger the scheduled task using the scheduler\n await scheduler.triggerTask('infrawallet-autoload-costs');\n\n response.json({\n status: 'ok',\n message: 'Cost data fetching task has been triggered. Check logs for execution details.',\n });\n } catch (error) {\n logger.error(`Error triggering cost data fetch task: ${error.message}`, { error });\n\n // Fall back to direct execution if task triggering fails\n try {\n logger.info('Falling back to direct execution of fetch and save costs');\n await fetchAndSaveCosts(options);\n response.json({\n status: 'ok',\n message: 'Cost data fetch completed successfully via direct execution.',\n });\n } catch (directError) {\n logger.error(`Direct cost data fetch failed: ${directError.message}`, { error: directError });\n response.status(500).json({\n status: 'error',\n message: 'Failed to fetch cost data. Check logs for more details.',\n });\n }\n }\n });\n\n router.post('/:walletName/delete_cost_items', async (request, response) => {\n const walletName = request.params.walletName;\n const granularity = request.body.granularity as string;\n const provider = request.body.provider as string;\n\n const wallet = await getWallet(database, walletName);\n if (wallet && granularity && provider) {\n const rowsDeleted = await deleteCostItems(database, wallet.id, provider, granularity);\n response.json({\n message: `Deleted ${rowsDeleted} ${granularity} ${provider} cost records in ${walletName}`,\n status: 'ok',\n });\n } else {\n response.status(404).json({ error: 'Wallet not found or missing parameters', status: 404 });\n }\n });\n\n router.get('/reports', async (request, response) => {\n const filters = request.query.filters as string;\n const tags = parseTags(request.query.tags as string);\n const groups = request.query.groups as string;\n const granularityString = request.query.granularity as string;\n const startTime = request.query.startTime as string;\n const endTime = request.query.endTime as string;\n const [entityNamespace, entityName] = decodeURI(request.query.entityName as string)?.split('/') || [];\n\n let reportFilters: ReportParameters = {\n filters,\n tags,\n groups,\n granularityString,\n startTime,\n endTime,\n entityNamespace,\n entityName,\n };\n if (additionalFilters.length > 0) {\n for (const filter of additionalFilters) {\n reportFilters = await filter.augmentFilters(reportFilters);\n }\n }\n const { reports, forecasts, clientErrors } = await getReports(reportFilters, config, database, cache, logger);\n\n if (clientErrors.length > 0) {\n response.status(207).json({ data: reports, errors: clientErrors, status: 207 });\n } else {\n response.json({ data: reports, forecasts: forecasts, errors: clientErrors, status: 200 });\n }\n });\n\n router.get('/tag-keys', async (request, response) => {\n const tags: Tag[] = [];\n const errors: CloudProviderError[] = [];\n\n const tagProvider = request.query.provider as string;\n const startTime = request.query.startTime as string;\n const endTime = request.query.endTime as string;\n const promises: Promise<void>[] = [];\n\n const conf = config.getConfig('backend.infraWallet.integrations');\n conf.keys().forEach((provider: string) => {\n if (provider.toLowerCase() === tagProvider.toLowerCase() && provider in COST_CLIENT_MAPPINGS) {\n const client: InfraWalletClient = COST_CLIENT_MAPPINGS[provider].create(config, database, cache, logger);\n const getTagKeys = (async () => {\n try {\n const clientResponse = await client.getTagKeys({\n startTime: startTime,\n endTime: endTime,\n });\n clientResponse.errors.forEach((e: CloudProviderError) => {\n errors.push(e);\n });\n clientResponse.tags.forEach((tag: Tag) => {\n tags.push(tag);\n });\n } catch (e) {\n logger.error(e);\n errors.push({\n provider: client.constructor.name,\n name: client.constructor.name,\n error: e.message,\n });\n }\n })();\n promises.push(getTagKeys);\n }\n });\n\n await Promise.all(promises);\n\n if (errors.length > 0) {\n response.status(207).json({ data: tags, errors: errors, status: 207 });\n } else {\n response.json({ data: tags, errors: errors, status: 200 });\n }\n });\n\n router.get('/tag-values', async (request, response) => {\n const tags: Tag[] = [];\n const errors: CloudProviderError[] = [];\n\n const startTime = request.query.startTime as string;\n const endTime = request.query.endTime as string;\n const tagKey = request.query.tag as string;\n const tagProvider = request.query.provider as string;\n const promises: Promise<void>[] = [];\n\n const conf = config.getConfig('backend.infraWallet.integrations');\n conf.keys().forEach((provider: string) => {\n if (provider in COST_CLIENT_MAPPINGS && provider.toLowerCase() === tagProvider.toLowerCase()) {\n const client: InfraWalletClient = COST_CLIENT_MAPPINGS[provider].create(config, database, cache, logger);\n const getTagValues = (async () => {\n try {\n const clientResponse = await client.getTagValues(\n {\n startTime: startTime,\n endTime: endTime,\n },\n tagKey,\n );\n clientResponse.errors.forEach((e: CloudProviderError) => {\n errors.push(e);\n });\n clientResponse.tags.forEach((tag: Tag) => {\n tags.push(tag);\n });\n } catch (e) {\n logger.error(e);\n errors.push({\n provider: client.constructor.name,\n name: client.constructor.name,\n error: e.message,\n });\n }\n })();\n promises.push(getTagValues);\n }\n });\n\n await Promise.all(promises);\n\n if (errors.length > 0) {\n response.status(207).json({ data: tags, errors: errors, status: 207 });\n } else {\n response.json({ data: tags, errors: errors, status: 200 });\n }\n });\n\n router.get('/:walletName/budgets', async (request, response) => {\n const walletName = request.params.walletName;\n const provider = request.query.provider as string;\n let budgets;\n\n if (provider) {\n budgets = await getBudget(database, walletName, provider);\n } else {\n budgets = await getBudgets(database, walletName);\n }\n\n response.json({ data: budgets, status: 200 });\n });\n\n router.put('/:walletName/budgets', async (request, response) => {\n const walletName = request.params.walletName;\n const result = await upsertBudget(database, walletName, request.body as Budget);\n response.json({ updated: result, status: 200 });\n });\n\n router.get('/custom-costs', async (_request, response) => {\n const customCosts = await getCustomCosts(database);\n\n // make it compatible with the SQLite database\n for (const cost of customCosts) {\n if (typeof cost.tags === 'string') {\n try {\n cost.tags = JSON.parse(cost.tags);\n } catch (error) {\n cost.tags = {};\n }\n }\n }\n\n response.json({ data: customCosts, status: 200 });\n });\n\n router.post('/custom-costs', async (request, response) => {\n const readOnly = config.getOptionalBoolean('infraWallet.settings.readOnly') ?? false;\n\n if (readOnly) {\n response.status(403).json({ error: 'API not enabled in read-only mode', status: 403 });\n return;\n }\n\n const updatedCustomCost = await createCustomCosts(database, request.body as CustomCost[]);\n response.json({ created: updatedCustomCost, status: 200 });\n });\n\n router.put('/custom-cost', async (request, response) => {\n const readOnly = config.getOptionalBoolean('infraWallet.settings.readOnly') ?? false;\n\n if (readOnly) {\n response.status(403).json({ error: 'API not enabled in read-only mode', status: 403 });\n return;\n }\n\n const updatedCustomCost = await updateOrInsertCustomCost(database, request.body as CustomCost);\n response.json({ updated: updatedCustomCost, status: 200 });\n });\n\n router.delete('/custom-cost', async (request, response) => {\n const readOnly = config.getOptionalBoolean('infraWallet.settings.readOnly') ?? false;\n\n if (readOnly) {\n response.status(403).json({ error: 'API not enabled in read-only mode', status: 403 });\n return;\n }\n\n const deletedCustomCost = await deleteCustomCost(database, request.body as CustomCost);\n response.json({ deleted: deletedCustomCost, status: 200 });\n });\n\n router.get('/:walletName/metrics', async (request, response) => {\n const walletName = request.params.walletName;\n const granularity = request.query.granularity as string;\n const startTime = request.query.startTime as string;\n const endTime = request.query.endTime as string;\n const promises: Promise<void>[] = [];\n const results: Metric[] = [];\n const errors: CloudProviderError[] = [];\n\n const conf = config.getConfig('backend.infraWallet.metricProviders');\n conf.keys().forEach((provider: string) => {\n if (provider in METRIC_PROVIDER_MAPPINGS) {\n const client: MetricProvider = METRIC_PROVIDER_MAPPINGS[provider].create(config, database, cache, logger);\n const fetchMetrics = (async () => {\n try {\n const metricResponse = await client.getMetrics({\n walletName: walletName,\n granularity: granularity,\n startTime: startTime,\n endTime: endTime,\n });\n metricResponse.errors.forEach((e: CloudProviderError) => {\n errors.push(e);\n });\n metricResponse.metrics.forEach((metric: Metric) => {\n results.push(metric);\n });\n } catch (e) {\n logger.error(e);\n errors.push({\n provider: client.constructor.name,\n name: client.constructor.name,\n error: e.message,\n });\n }\n })();\n promises.push(fetchMetrics);\n }\n });\n\n await Promise.all(promises);\n\n if (errors.length > 0) {\n response.status(207).json({ data: results, errors: errors, status: 207 });\n } else {\n response.json({ data: results, errors: errors, status: 200 });\n }\n });\n\n router.get('/:walletName', async (request, response) => {\n const walletName = request.params.walletName;\n const wallet = await getWallet(database, walletName);\n if (wallet === undefined) {\n response.status(404).json({ error: 'Wallet not found', status: 404 });\n return;\n }\n\n response.json({ data: wallet, status: 200 });\n });\n\n router.get('/:walletName/metrics-setting', async (request, response) => {\n const walletName = request.params.walletName;\n const metricSettings = await getWalletMetricSettings(database, walletName);\n response.json({ data: metricSettings, status: 200 });\n });\n\n router.get('/metric/metric-configs', async (_request, response) => {\n const conf = config.getConfig('backend.infraWallet.metricProviders');\n const configNames: { metric_provider: string; config_name: string }[] = [];\n conf.keys().forEach((provider: string) => {\n const configs = conf.getOptionalConfigArray(provider);\n if (configs) {\n configs.forEach(c => {\n configNames.push({ metric_provider: provider, config_name: c.getString('name') });\n });\n }\n });\n\n response.json({ data: configNames, status: 200 });\n });\n\n router.put('/:walletName/metrics-setting', async (request, response) => {\n const readOnly = config.getOptionalBoolean('infraWallet.settings.readOnly') ?? false;\n\n if (readOnly) {\n response.status(403).json({ error: 'API not enabled in read-only mode', status: 403 });\n return;\n }\n\n const updatedMetricSetting = await updateOrInsertWalletMetricSetting(database, request.body as MetricSetting);\n response.json({ updated: updatedMetricSetting, status: 200 });\n });\n\n router.delete('/:walletName/metrics-setting', async (request, response) => {\n const readOnly = config.getOptionalBoolean('infraWallet.settings.readOnly') ?? false;\n\n if (readOnly) {\n response.status(403).json({ error: 'API not enabled in read-only mode', status: 403 });\n return;\n }\n\n const deletedMetricSetting = await deleteWalletMetricSetting(database, request.body as MetricSetting);\n response.json({ deleted: deletedMetricSetting, status: 200 });\n });\n\n const middleware = MiddlewareFactory.create({ config, logger });\n router.use(middleware.error());\n\n return router;\n}\n"],"names":["resolvePackagePath","GRANULARITY","CategoryMappingService","COST_CLIENT_MAPPINGS","tagsToString","parseFilters","Router","express","fetchAndSaveCosts","getWallet","deleteCostItems","parseTags","getBudget","getBudgets","upsertBudget","getCustomCosts","createCustomCosts","updateOrInsertCustomCost","deleteCustomCost","METRIC_PROVIDER_MAPPINGS","getWalletMetricSettings","updateOrInsertWalletMetricSetting","deleteWalletMetricSetting","MiddlewareFactory"],"mappings":";;;;;;;;;;;;;;;;;;;;AA4BA,eAAe,cAAc,QAAA,EAA2B;AAEtD,EAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,SAAA,EAAU;AACxC,EAAA,MAAM,aAAA,GAAgBA,mCAAA,CAAmB,4CAAA,EAA8C,YAAY,CAAA;AACnG,EAAA,IAAI,CAAC,QAAA,CAAS,UAAA,EAAY,IAAA,EAAM;AAC9B,IAAA,MAAM,MAAA,CAAO,QAAQ,MAAA,CAAO;AAAA,MAC1B,SAAA,EAAW;AAAA,KACZ,CAAA;AAAA;AAIH,EAAA,MAAM,QAAA,GAAWA,mCAAA,CAAmB,4CAAA,EAA8C,OAAO,CAAA;AACzF,EAAA,MAAM,OAAO,IAAA,CAAK,GAAA,CAAI,EAAE,SAAA,EAAW,UAAU,CAAA;AAC/C;AAEA,eAAe,UAAA,CACb,eAAA,EACA,MAAA,EACA,QAAA,EACA,OACA,MAAA,EACuG;AACvG,EAAA,MAAM,EAAE,OAAA,EAAS,IAAA,EAAM,QAAQ,iBAAA,EAAmB,SAAA,EAAW,SAAQ,GAAI,eAAA;AACzE,EAAA,MAAM,WAA4B,EAAC;AACnC,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,IAAI,YAAoC,EAAC;AACzC,EAAA,MAAM,SAA+B,EAAC;AAEtC,EAAA,MAAM,WAAA,GAA2B,OAAO,MAAA,CAAOC,kBAAW,EAAE,QAAA,CAAS,iBAAgC,CAAA,GAChG,iBAAA,GACDA,kBAAA,CAAY,OAAA;AAGhB,EAAA,MAAM,eAAsC,EAAC;AAC7C,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,MAAM,QAAA,GAAW,GAAA,CAAI,QAAA,CAAS,WAAA,EAAY;AAC1C,IAAA,IAAI,CAAC,YAAA,CAAa,QAAQ,CAAA,EAAG;AAC3B,MAAA,YAAA,CAAa,QAAQ,IAAI,EAAC;AAAA;AAG5B,IAAA,YAAA,CAAa,QAAQ,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAAA;AAGjC,EAAA,MAAM,sBAAA,GAAyBC,8CAAuB,WAAA,EAAY;AAClE,EAAA,MAAM,uBAAuB,uBAAA,EAAwB;AAErD,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,SAAA,CAAU,kCAAkC,CAAA;AAChE,EAAA,IAAA,CACG,IAAA,GACA,MAAA,CAAO,CAAC,QAAQ,CAAC,CAAA,CACjB,OAAA,CAAQ,CAAC,QAAA,KAAqB;AAC7B,IAAA,IAAI,YAAYC,2BAAA,EAAsB;AACpC,MAAA,MAAM,MAAA,GAA4BA,4BAAqB,QAAQ,CAAA,CAAE,OAAO,MAAA,EAAQ,QAAA,EAAU,OAAO,MAAM,CAAA;AACvG,MAAA,MAAM,mBAAmB,YAAY;AACnC,QAAA,IAAI;AACF,UAAA,MAAM,cAAA,GAAiB,MAAM,MAAA,CAAO,cAAA,CAAe;AAAA,YACjD,OAAA;AAAA,YACA,MAAMC,sBAAA,CAAa,YAAA,CAAa,QAAA,CAAS,WAAA,EAAa,CAAC,CAAA;AAAA,YACvD,MAAA;AAAA,YACA,WAAA;AAAA,YACA,SAAA;AAAA,YACA;AAAA,WACD,CAAA;AACD,UAAA,cAAA,CAAe,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAA,KAA0B;AACvD,YAAA,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,WACd,CAAA;AACD,UAAA,cAAA,CAAe,OAAA,CAAQ,OAAA,CAAQ,CAAC,IAAA,KAAiB;AAC/C,YAAA,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,WAClB,CAAA;AACD,UAAA,IAAI,eAAe,SAAA,EAAW;AAC5B,YAAA,SAAA,GAAY,EAAE,GAAG,SAAA,EAAW,GAAG,eAAe,SAAA,EAAU;AAAA;AAC1D,iBACO,CAAA,EAAG;AACV,UAAA,MAAA,CAAO,MAAM,CAAC,CAAA;AACd,UAAA,MAAA,CAAO,IAAA,CAAK;AAAA,YACV,QAAA,EAAU,OAAO,WAAA,CAAY,IAAA;AAAA,YAC7B,IAAA,EAAM,OAAO,WAAA,CAAY,IAAA;AAAA,YACzB,OAAO,CAAA,CAAE;AAAA,WACV,CAAA;AAAA;AACH,OACF,GAAG;AACH,MAAA,QAAA,CAAS,KAAK,eAAe,CAAA;AAAA;AAC/B,GACD,CAAA;AAEH,EAAA,MAAM,OAAA,CAAQ,IAAI,QAAQ,CAAA;AAE1B,EAAA,MAAM,aAAA,GAAgBC,uBAAa,OAAO,CAAA;AAE1C,EAAA,MAAM,eAAA,GAAkB,OAAA,CAAQ,MAAA,CAAO,CAAA,MAAA,KAAU;AAC/C,IAAA,OAAO,MAAA,CAAO,QAAQ,aAAa,CAAA,CAAE,MAAM,CAAC,CAAC,GAAA,EAAK,MAAM,CAAA,KAAM;AAC5D,MAAA,MAAM,WAAA,GAAc,OAAO,GAAG,CAAA;AAC9B,MAAA,IAAI,OAAO,gBAAgB,QAAA,EAAU;AACnC,QAAA,OAAO,KAAA;AAAA;AAET,MAAA,OAAO,MAAA,CAAO,SAAS,WAAW,CAAA;AAAA,KACnC,CAAA;AAAA,GACF,CAAA;AAED,EAAA,OAAO,EAAE,OAAA,EAAS,eAAA,EAAiB,YAAA,EAAc,QAAQ,SAAA,EAAqB;AAChF;AAEA,eAAsB,aAAa,OAAA,EAAiD;AAClF,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,WAAW,KAAA,EAAO,QAAA,EAAU,mBAAkB,GAAI,OAAA;AAE1E,EAAA,MAAM,cAAc,QAAQ,CAAA;AAG5B,EAAAH,6CAAA,CAAuB,YAAA,CAAa,OAAO,MAAM,CAAA;AAEjD,EAAA,MAAM,SAASI,uBAAA,EAAO;AACtB,EAAA,MAAA,CAAO,GAAA,CAAIC,wBAAA,CAAQ,IAAA,EAAM,CAAA;AAEzB,EAAA,MAAA,CAAO,GAAA,CAAI,SAAA,EAAW,CAAC,CAAA,EAAG,QAAA,KAAa;AACrC,IAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,IAAA,QAAA,CAAS,IAAA,CAAK,EAAE,MAAA,EAAQ,IAAA,EAAM,CAAA;AAAA,GAC/B,CAAA;AAGD,EAAA,MAAA,CAAO,GAAA,CAAI,uBAAA,EAAyB,OAAO,CAAA,EAAG,QAAA,KAAa;AACzD,IAAA,IAAI;AAEF,MAAA,MAAM,SAAA,CAAU,YAAY,4BAA4B,CAAA;AAExD,MAAA,QAAA,CAAS,IAAA,CAAK;AAAA,QACZ,MAAA,EAAQ,IAAA;AAAA,QACR,OAAA,EAAS;AAAA,OACV,CAAA;AAAA,aACM,KAAA,EAAO;AACd,MAAA,MAAA,CAAO,MAAM,CAAA,uCAAA,EAA0C,KAAA,CAAM,OAAO,CAAA,CAAA,EAAI,EAAE,OAAO,CAAA;AAGjF,MAAA,IAAI;AACF,QAAA,MAAA,CAAO,KAAK,0DAA0D,CAAA;AACtE,QAAA,MAAMC,oCAAkB,OAAO,CAAA;AAC/B,QAAA,QAAA,CAAS,IAAA,CAAK;AAAA,UACZ,MAAA,EAAQ,IAAA;AAAA,UACR,OAAA,EAAS;AAAA,SACV,CAAA;AAAA,eACM,WAAA,EAAa;AACpB,QAAA,MAAA,CAAO,KAAA,CAAM,kCAAkC,WAAA,CAAY,OAAO,IAAI,EAAE,KAAA,EAAO,aAAa,CAAA;AAC5F,QAAA,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,UACxB,MAAA,EAAQ,OAAA;AAAA,UACR,OAAA,EAAS;AAAA,SACV,CAAA;AAAA;AACH;AACF,GACD,CAAA;AAED,EAAA,MAAA,CAAO,IAAA,CAAK,gCAAA,EAAkC,OAAO,OAAA,EAAS,QAAA,KAAa;AACzE,IAAA,MAAM,UAAA,GAAa,QAAQ,MAAA,CAAO,UAAA;AAClC,IAAA,MAAM,WAAA,GAAc,QAAQ,IAAA,CAAK,WAAA;AACjC,IAAA,MAAM,QAAA,GAAW,QAAQ,IAAA,CAAK,QAAA;AAE9B,IAAA,MAAM,MAAA,GAAS,MAAMC,iCAAA,CAAU,QAAA,EAAU,UAAU,CAAA;AACnD,IAAA,IAAI,MAAA,IAAU,eAAe,QAAA,EAAU;AACrC,MAAA,MAAM,cAAc,MAAMC,wBAAA,CAAgB,UAAU,MAAA,CAAO,EAAA,EAAI,UAAU,WAAW,CAAA;AACpF,MAAA,QAAA,CAAS,IAAA,CAAK;AAAA,QACZ,OAAA,EAAS,WAAW,WAAW,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA,EAAI,QAAQ,oBAAoB,UAAU,CAAA,CAAA;AAAA,QACxF,MAAA,EAAQ;AAAA,OACT,CAAA;AAAA,KACH,MAAO;AACL,MAAA,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,wCAAA,EAA0C,MAAA,EAAQ,GAAA,EAAK,CAAA;AAAA;AAC5F,GACD,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,UAAA,EAAY,OAAO,OAAA,EAAS,QAAA,KAAa;AAClD,IAAA,MAAM,OAAA,GAAU,QAAQ,KAAA,CAAM,OAAA;AAC9B,IAAA,MAAM,IAAA,GAAOC,mBAAA,CAAU,OAAA,CAAQ,KAAA,CAAM,IAAc,CAAA;AACnD,IAAA,MAAM,MAAA,GAAS,QAAQ,KAAA,CAAM,MAAA;AAC7B,IAAA,MAAM,iBAAA,GAAoB,QAAQ,KAAA,CAAM,WAAA;AACxC,IAAA,MAAM,SAAA,GAAY,QAAQ,KAAA,CAAM,SAAA;AAChC,IAAA,MAAM,OAAA,GAAU,QAAQ,KAAA,CAAM,OAAA;AAC9B,IAAA,MAAM,CAAC,eAAA,EAAiB,UAAU,CAAA,GAAI,SAAA,CAAU,OAAA,CAAQ,KAAA,CAAM,UAAoB,CAAA,EAAG,KAAA,CAAM,GAAG,CAAA,IAAK,EAAC;AAEpG,IAAA,IAAI,aAAA,GAAkC;AAAA,MACpC,OAAA;AAAA,MACA,IAAA;AAAA,MACA,MAAA;AAAA,MACA,iBAAA;AAAA,MACA,SAAA;AAAA,MACA,OAAA;AAAA,MACA,eAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,IAAI,iBAAA,CAAkB,SAAS,CAAA,EAAG;AAChC,MAAA,KAAA,MAAW,UAAU,iBAAA,EAAmB;AACtC,QAAA,aAAA,GAAgB,MAAM,MAAA,CAAO,cAAA,CAAe,aAAa,CAAA;AAAA;AAC3D;AAEF,IAAA,MAAM,EAAE,OAAA,EAAS,SAAA,EAAW,YAAA,EAAa,GAAI,MAAM,UAAA,CAAW,aAAA,EAAe,MAAA,EAAQ,QAAA,EAAU,KAAA,EAAO,MAAM,CAAA;AAE5G,IAAA,IAAI,YAAA,CAAa,SAAS,CAAA,EAAG;AAC3B,MAAA,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,IAAA,EAAM,OAAA,EAAS,MAAA,EAAQ,YAAA,EAAc,MAAA,EAAQ,GAAA,EAAK,CAAA;AAAA,KAChF,MAAO;AACL,MAAA,QAAA,CAAS,IAAA,CAAK,EAAE,IAAA,EAAM,OAAA,EAAS,WAAsB,MAAA,EAAQ,YAAA,EAAc,MAAA,EAAQ,GAAA,EAAK,CAAA;AAAA;AAC1F,GACD,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,WAAA,EAAa,OAAO,OAAA,EAAS,QAAA,KAAa;AACnD,IAAA,MAAM,OAAc,EAAC;AACrB,IAAA,MAAM,SAA+B,EAAC;AAEtC,IAAA,MAAM,WAAA,GAAc,QAAQ,KAAA,CAAM,QAAA;AAClC,IAAA,MAAM,SAAA,GAAY,QAAQ,KAAA,CAAM,SAAA;AAChC,IAAA,MAAM,OAAA,GAAU,QAAQ,KAAA,CAAM,OAAA;AAC9B,IAAA,MAAM,WAA4B,EAAC;AAEnC,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,SAAA,CAAU,kCAAkC,CAAA;AAChE,IAAA,IAAA,CAAK,IAAA,EAAK,CAAE,OAAA,CAAQ,CAAC,QAAA,KAAqB;AACxC,MAAA,IAAI,SAAS,WAAA,EAAY,KAAM,YAAY,WAAA,EAAY,IAAK,YAAYR,2BAAA,EAAsB;AAC5F,QAAA,MAAM,MAAA,GAA4BA,4BAAqB,QAAQ,CAAA,CAAE,OAAO,MAAA,EAAQ,QAAA,EAAU,OAAO,MAAM,CAAA;AACvG,QAAA,MAAM,cAAc,YAAY;AAC9B,UAAA,IAAI;AACF,YAAA,MAAM,cAAA,GAAiB,MAAM,MAAA,CAAO,UAAA,CAAW;AAAA,cAC7C,SAAA;AAAA,cACA;AAAA,aACD,CAAA;AACD,YAAA,cAAA,CAAe,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAA,KAA0B;AACvD,cAAA,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,aACd,CAAA;AACD,YAAA,cAAA,CAAe,IAAA,CAAK,OAAA,CAAQ,CAAC,GAAA,KAAa;AACxC,cAAA,IAAA,CAAK,KAAK,GAAG,CAAA;AAAA,aACd,CAAA;AAAA,mBACM,CAAA,EAAG;AACV,YAAA,MAAA,CAAO,MAAM,CAAC,CAAA;AACd,YAAA,MAAA,CAAO,IAAA,CAAK;AAAA,cACV,QAAA,EAAU,OAAO,WAAA,CAAY,IAAA;AAAA,cAC7B,IAAA,EAAM,OAAO,WAAA,CAAY,IAAA;AAAA,cACzB,OAAO,CAAA,CAAE;AAAA,aACV,CAAA;AAAA;AACH,SACF,GAAG;AACH,QAAA,QAAA,CAAS,KAAK,UAAU,CAAA;AAAA;AAC1B,KACD,CAAA;AAED,IAAA,MAAM,OAAA,CAAQ,IAAI,QAAQ,CAAA;AAE1B,IAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,MAAA,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,MAAM,IAAA,EAAM,MAAA,EAAgB,MAAA,EAAQ,GAAA,EAAK,CAAA;AAAA,KACvE,MAAO;AACL,MAAA,QAAA,CAAS,KAAK,EAAE,IAAA,EAAM,MAAM,MAAA,EAAgB,MAAA,EAAQ,KAAK,CAAA;AAAA;AAC3D,GACD,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,aAAA,EAAe,OAAO,OAAA,EAAS,QAAA,KAAa;AACrD,IAAA,MAAM,OAAc,EAAC;AACrB,IAAA,MAAM,SAA+B,EAAC;AAEtC,IAAA,MAAM,SAAA,GAAY,QAAQ,KAAA,CAAM,SAAA;AAChC,IAAA,MAAM,OAAA,GAAU,QAAQ,KAAA,CAAM,OAAA;AAC9B,IAAA,MAAM,MAAA,GAAS,QAAQ,KAAA,CAAM,GAAA;AAC7B,IAAA,MAAM,WAAA,GAAc,QAAQ,KAAA,CAAM,QAAA;AAClC,IAAA,MAAM,WAA4B,EAAC;AAEnC,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,SAAA,CAAU,kCAAkC,CAAA;AAChE,IAAA,IAAA,CAAK,IAAA,EAAK,CAAE,OAAA,CAAQ,CAAC,QAAA,KAAqB;AACxC,MAAA,IAAI,YAAYA,2BAAA,IAAwB,QAAA,CAAS,aAAY,KAAM,WAAA,CAAY,aAAY,EAAG;AAC5F,QAAA,MAAM,MAAA,GAA4BA,4BAAqB,QAAQ,CAAA,CAAE,OAAO,MAAA,EAAQ,QAAA,EAAU,OAAO,MAAM,CAAA;AACvG,QAAA,MAAM,gBAAgB,YAAY;AAChC,UAAA,IAAI;AACF,YAAA,MAAM,cAAA,GAAiB,MAAM,MAAA,CAAO,YAAA;AAAA,cAClC;AAAA,gBACE,SAAA;AAAA,gBACA;AAAA,eACF;AAAA,cACA;AAAA,aACF;AACA,YAAA,cAAA,CAAe,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAA,KAA0B;AACvD,cAAA,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,aACd,CAAA;AACD,YAAA,cAAA,CAAe,IAAA,CAAK,OAAA,CAAQ,CAAC,GAAA,KAAa;AACxC,cAAA,IAAA,CAAK,KAAK,GAAG,CAAA;AAAA,aACd,CAAA;AAAA,mBACM,CAAA,EAAG;AACV,YAAA,MAAA,CAAO,MAAM,CAAC,CAAA;AACd,YAAA,MAAA,CAAO,IAAA,CAAK;AAAA,cACV,QAAA,EAAU,OAAO,WAAA,CAAY,IAAA;AAAA,cAC7B,IAAA,EAAM,OAAO,WAAA,CAAY,IAAA;AAAA,cACzB,OAAO,CAAA,CAAE;AAAA,aACV,CAAA;AAAA;AACH,SACF,GAAG;AACH,QAAA,QAAA,CAAS,KAAK,YAAY,CAAA;AAAA;AAC5B,KACD,CAAA;AAED,IAAA,MAAM,OAAA,CAAQ,IAAI,QAAQ,CAAA;AAE1B,IAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,MAAA,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,MAAM,IAAA,EAAM,MAAA,EAAgB,MAAA,EAAQ,GAAA,EAAK,CAAA;AAAA,KACvE,MAAO;AACL,MAAA,QAAA,CAAS,KAAK,EAAE,IAAA,EAAM,MAAM,MAAA,EAAgB,MAAA,EAAQ,KAAK,CAAA;AAAA;AAC3D,GACD,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,sBAAA,EAAwB,OAAO,OAAA,EAAS,QAAA,KAAa;AAC9D,IAAA,MAAM,UAAA,GAAa,QAAQ,MAAA,CAAO,UAAA;AAClC,IAAA,MAAM,QAAA,GAAW,QAAQ,KAAA,CAAM,QAAA;AAC/B,IAAA,IAAI,OAAA;AAEJ,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,OAAA,GAAU,MAAMS,gBAAA,CAAU,QAAA,EAAU,UAAA,EAAY,QAAQ,CAAA;AAAA,KAC1D,MAAO;AACL,MAAA,OAAA,GAAU,MAAMC,iBAAA,CAAW,QAAA,EAAU,UAAU,CAAA;AAAA;AAGjD,IAAA,QAAA,CAAS,KAAK,EAAE,IAAA,EAAM,OAAA,EAAS,MAAA,EAAQ,KAAK,CAAA;AAAA,GAC7C,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,sBAAA,EAAwB,OAAO,OAAA,EAAS,QAAA,KAAa;AAC9D,IAAA,MAAM,UAAA,GAAa,QAAQ,MAAA,CAAO,UAAA;AAClC,IAAA,MAAM,SAAS,MAAMC,mBAAA,CAAa,QAAA,EAAU,UAAA,EAAY,QAAQ,IAAc,CAAA;AAC9E,IAAA,QAAA,CAAS,KAAK,EAAE,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAA;AAAA,GAC/C,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,eAAA,EAAiB,OAAO,QAAA,EAAU,QAAA,KAAa;AACxD,IAAA,MAAM,WAAA,GAAc,MAAMC,yBAAA,CAAe,QAAQ,CAAA;AAGjD,IAAA,KAAA,MAAW,QAAQ,WAAA,EAAa;AAC9B,MAAA,IAAI,OAAO,IAAA,CAAK,IAAA,KAAS,QAAA,EAAU;AACjC,QAAA,IAAI;AACF,UAAA,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAAA,iBACzB,KAAA,EAAO;AACd,UAAA,IAAA,CAAK,OAAO,EAAC;AAAA;AACf;AACF;AAGF,IAAA,QAAA,CAAS,KAAK,EAAE,IAAA,EAAM,WAAA,EAAa,MAAA,EAAQ,KAAK,CAAA;AAAA,GACjD,CAAA;AAED,EAAA,MAAA,CAAO,IAAA,CAAK,eAAA,EAAiB,OAAO,OAAA,EAAS,QAAA,KAAa;AACxD,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,kBAAA,CAAmB,+BAA+B,CAAA,IAAK,KAAA;AAE/E,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mCAAA,EAAqC,MAAA,EAAQ,GAAA,EAAK,CAAA;AACrF,MAAA;AAAA;AAGF,IAAA,MAAM,iBAAA,GAAoB,MAAMC,4BAAA,CAAkB,QAAA,EAAU,QAAQ,IAAoB,CAAA;AACxF,IAAA,QAAA,CAAS,KAAK,EAAE,OAAA,EAAS,iBAAA,EAAmB,MAAA,EAAQ,KAAK,CAAA;AAAA,GAC1D,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,cAAA,EAAgB,OAAO,OAAA,EAAS,QAAA,KAAa;AACtD,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,kBAAA,CAAmB,+BAA+B,CAAA,IAAK,KAAA;AAE/E,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mCAAA,EAAqC,MAAA,EAAQ,GAAA,EAAK,CAAA;AACrF,MAAA;AAAA;AAGF,IAAA,MAAM,iBAAA,GAAoB,MAAMC,mCAAA,CAAyB,QAAA,EAAU,QAAQ,IAAkB,CAAA;AAC7F,IAAA,QAAA,CAAS,KAAK,EAAE,OAAA,EAAS,iBAAA,EAAmB,MAAA,EAAQ,KAAK,CAAA;AAAA,GAC1D,CAAA;AAED,EAAA,MAAA,CAAO,MAAA,CAAO,cAAA,EAAgB,OAAO,OAAA,EAAS,QAAA,KAAa;AACzD,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,kBAAA,CAAmB,+BAA+B,CAAA,IAAK,KAAA;AAE/E,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mCAAA,EAAqC,MAAA,EAAQ,GAAA,EAAK,CAAA;AACrF,MAAA;AAAA;AAGF,IAAA,MAAM,iBAAA,GAAoB,MAAMC,2BAAA,CAAiB,QAAA,EAAU,QAAQ,IAAkB,CAAA;AACrF,IAAA,QAAA,CAAS,KAAK,EAAE,OAAA,EAAS,iBAAA,EAAmB,MAAA,EAAQ,KAAK,CAAA;AAAA,GAC1D,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,sBAAA,EAAwB,OAAO,OAAA,EAAS,QAAA,KAAa;AAC9D,IAAA,MAAM,UAAA,GAAa,QAAQ,MAAA,CAAO,UAAA;AAClC,IAAA,MAAM,WAAA,GAAc,QAAQ,KAAA,CAAM,WAAA;AAClC,IAAA,MAAM,SAAA,GAAY,QAAQ,KAAA,CAAM,SAAA;AAChC,IAAA,MAAM,OAAA,GAAU,QAAQ,KAAA,CAAM,OAAA;AAC9B,IAAA,MAAM,WAA4B,EAAC;AACnC,IAAA,MAAM,UAAoB,EAAC;AAC3B,IAAA,MAAM,SAA+B,EAAC;AAEtC,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,SAAA,CAAU,qCAAqC,CAAA;AACnE,IAAA,IAAA,CAAK,IAAA,EAAK,CAAE,OAAA,CAAQ,CAAC,QAAA,KAAqB;AACxC,MAAA,IAAI,YAAYC,+BAAA,EAA0B;AACxC,QAAA,MAAM,MAAA,GAAyBA,gCAAyB,QAAQ,CAAA,CAAE,OAAO,MAAA,EAAQ,QAAA,EAAU,OAAO,MAAM,CAAA;AACxG,QAAA,MAAM,gBAAgB,YAAY;AAChC,UAAA,IAAI;AACF,YAAA,MAAM,cAAA,GAAiB,MAAM,MAAA,CAAO,UAAA,CAAW;AAAA,cAC7C,UAAA;AAAA,cACA,WAAA;AAAA,cACA,SAAA;AAAA,cACA;AAAA,aACD,CAAA;AACD,YAAA,cAAA,CAAe,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAA,KAA0B;AACvD,cAAA,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,aACd,CAAA;AACD,YAAA,cAAA,CAAe,OAAA,CAAQ,OAAA,CAAQ,CAAC,MAAA,KAAmB;AACjD,cAAA,OAAA,CAAQ,KAAK,MAAM,CAAA;AAAA,aACpB,CAAA;AAAA,mBACM,CAAA,EAAG;AACV,YAAA,MAAA,CAAO,MAAM,CAAC,CAAA;AACd,YAAA,MAAA,CAAO,IAAA,CAAK;AAAA,cACV,QAAA,EAAU,OAAO,WAAA,CAAY,IAAA;AAAA,cAC7B,IAAA,EAAM,OAAO,WAAA,CAAY,IAAA;AAAA,cACzB,OAAO,CAAA,CAAE;AAAA,aACV,CAAA;AAAA;AACH,SACF,GAAG;AACH,QAAA,QAAA,CAAS,KAAK,YAAY,CAAA;AAAA;AAC5B,KACD,CAAA;AAED,IAAA,MAAM,OAAA,CAAQ,IAAI,QAAQ,CAAA;AAE1B,IAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,MAAA,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,MAAM,OAAA,EAAS,MAAA,EAAgB,MAAA,EAAQ,GAAA,EAAK,CAAA;AAAA,KAC1E,MAAO;AACL,MAAA,QAAA,CAAS,KAAK,EAAE,IAAA,EAAM,SAAS,MAAA,EAAgB,MAAA,EAAQ,KAAK,CAAA;AAAA;AAC9D,GACD,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,cAAA,EAAgB,OAAO,OAAA,EAAS,QAAA,KAAa;AACtD,IAAA,MAAM,UAAA,GAAa,QAAQ,MAAA,CAAO,UAAA;AAClC,IAAA,MAAM,MAAA,GAAS,MAAMV,iCAAA,CAAU,QAAA,EAAU,UAAU,CAAA;AACnD,IAAA,IAAI,WAAW,MAAA,EAAW;AACxB,MAAA,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,kBAAA,EAAoB,MAAA,EAAQ,GAAA,EAAK,CAAA;AACpE,MAAA;AAAA;AAGF,IAAA,QAAA,CAAS,KAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAA;AAAA,GAC5C,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,8BAAA,EAAgC,OAAO,OAAA,EAAS,QAAA,KAAa;AACtE,IAAA,MAAM,UAAA,GAAa,QAAQ,MAAA,CAAO,UAAA;AAClC,IAAA,MAAM,cAAA,GAAiB,MAAMW,+CAAA,CAAwB,QAAA,EAAU,UAAU,CAAA;AACzE,IAAA,QAAA,CAAS,KAAK,EAAE,IAAA,EAAM,cAAA,EAAgB,MAAA,EAAQ,KAAK,CAAA;AAAA,GACpD,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,wBAAA,EAA0B,OAAO,QAAA,EAAU,QAAA,KAAa;AACjE,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,SAAA,CAAU,qCAAqC,CAAA;AACnE,IAAA,MAAM,cAAkE,EAAC;AACzE,IAAA,IAAA,CAAK,IAAA,EAAK,CAAE,OAAA,CAAQ,CAAC,QAAA,KAAqB;AACxC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,sBAAA,CAAuB,QAAQ,CAAA;AACpD,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,OAAA,CAAQ,QAAQ,CAAA,CAAA,KAAK;AACnB,UAAA,WAAA,CAAY,IAAA,CAAK,EAAE,eAAA,EAAiB,QAAA,EAAU,aAAa,CAAA,CAAE,SAAA,CAAU,MAAM,CAAA,EAAG,CAAA;AAAA,SACjF,CAAA;AAAA;AACH,KACD,CAAA;AAED,IAAA,QAAA,CAAS,KAAK,EAAE,IAAA,EAAM,WAAA,EAAa,MAAA,EAAQ,KAAK,CAAA;AAAA,GACjD,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,8BAAA,EAAgC,OAAO,OAAA,EAAS,QAAA,KAAa;AACtE,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,kBAAA,CAAmB,+BAA+B,CAAA,IAAK,KAAA;AAE/E,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mCAAA,EAAqC,MAAA,EAAQ,GAAA,EAAK,CAAA;AACrF,MAAA;AAAA;AAGF,IAAA,MAAM,oBAAA,GAAuB,MAAMC,yDAAA,CAAkC,QAAA,EAAU,QAAQ,IAAqB,CAAA;AAC5G,IAAA,QAAA,CAAS,KAAK,EAAE,OAAA,EAAS,oBAAA,EAAsB,MAAA,EAAQ,KAAK,CAAA;AAAA,GAC7D,CAAA;AAED,EAAA,MAAA,CAAO,MAAA,CAAO,8BAAA,EAAgC,OAAO,OAAA,EAAS,QAAA,KAAa;AACzE,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,kBAAA,CAAmB,+BAA+B,CAAA,IAAK,KAAA;AAE/E,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,mCAAA,EAAqC,MAAA,EAAQ,GAAA,EAAK,CAAA;AACrF,MAAA;AAAA;AAGF,IAAA,MAAM,oBAAA,GAAuB,MAAMC,iDAAA,CAA0B,QAAA,EAAU,QAAQ,IAAqB,CAAA;AACpG,IAAA,QAAA,CAAS,KAAK,EAAE,OAAA,EAAS,oBAAA,EAAsB,MAAA,EAAQ,KAAK,CAAA;AAAA,GAC7D,CAAA;AAED,EAAA,MAAM,aAAaC,gCAAA,CAAkB,MAAA,CAAO,EAAE,MAAA,EAAQ,QAAQ,CAAA;AAC9D,EAAA,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,KAAA,EAAO,CAAA;AAE7B,EAAA,OAAO,MAAA;AACT;;;;"}
|