@electrolux-oss/plugin-infrawallet-backend 1.1.0-20251218080407-fbaf733 → 1.1.0-20260115072024-d6f33e2

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.
@@ -194,6 +194,25 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
194
194
  }
195
195
  return costs;
196
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
+ }
197
216
  async transformCostsData(subAccountConfig, query, costResponse) {
198
217
  const tags = subAccountConfig.getOptionalStringArray("tags");
199
218
  const tagKeyValues = {};
@@ -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 // 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 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":";;;;;;;;;;;;;;;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;AAE5C,IAAA,MAAM,SAAA,GAAYC,uBAAA,CAAO,GAAA,CAAI,QAAA,CAAS,KAAA,CAAM,WAAW,EAAE,CAAC,CAAA,CAAE,OAAA,CAAQ,OAAO,CAAA;AAC3E,IAAA,MAAM,OAAA,GAAUA,uBAAA,CAAO,GAAA,CAAI,QAAA,CAAS,KAAA,CAAM,SAAS,EAAE,CAAC,CAAA,CAAE,OAAA,CAAQ,OAAO,CAAA;AACvE,IAAA,MAAM,gBAAA,GAAmBA,wBAAO,GAAA,EAAI,CAAE,QAAQ,OAAO,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,QAAQ,CAAA;AAI3E,IAAA,IAAI,SAAA,CAAU,QAAA,CAAS,gBAAgB,CAAA,EAAG;AACxC,MAAA,MAAM,iBAAA,GAAoBA,uBAAA,CAAO,GAAA,CAAI,OAAA,EAAS,gBAAA,CAAiB,OAAM,CAAE,QAAA,CAAS,CAAA,EAAG,OAAO,CAAC,CAAA;AAE3F,MAAA,MAAM,aAAA,GAAgB,CAAA;AACtB,MAAA,IAAI,UAAA,GAAa,UAAU,KAAA,EAAM;AAEjC,MAAA,OAAO,UAAA,CAAW,cAAA,CAAe,iBAAiB,CAAA,EAAG;AACnD,QAAA,IAAI,WAAW,UAAA,CAAW,KAAA,GAAQ,GAAA,CAAI,aAAA,GAAgB,GAAG,QAAQ,CAAA;AACjE,QAAA,IAAI,QAAA,CAAS,OAAA,CAAQ,iBAAiB,CAAA,EAAG;AACvC,UAAA,QAAA,GAAW,kBAAkB,KAAA,EAAM;AAAA;AAGrC,QAAA,MAAM,cAAc,QAAA,CAAS,KAAA,EAAM,CAAE,GAAA,CAAI,GAAG,OAAO,CAAA;AAEnD,QAAA,MAAM,cAAA,GAAiD,MAAM,MAAA,CAAO,sBAAA,CAAuB;AAAA,UACzF,UAAA,EAAY,UAAA;AAAA,UACZ,QAAA,EAAU,WAAA;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,UAAA,CAAW,KAAA,EAAM,CAAE,GAAA,CAAI,eAAe,QAAQ,CAAA;AAAA;AAC7D;AAKF,IAAA,IAAI,OAAA,CAAQ,aAAA,CAAc,gBAAgB,CAAA,EAAG;AAC3C,MAAA,MAAM,kBAAA,GAAqBF,uBAAA,CAAO,GAAA,CAAI,SAAA,EAAW,gBAAgB,CAAA;AACjE,MAAA,MAAM,aAAa,OAAA,CAAQ,KAAA,EAAM,CAAE,GAAA,CAAI,GAAG,OAAO,CAAA;AAEjD,MAAA,MAAM,aAAA,GAAgD,MAAM,MAAA,CAAO,qBAAA,CAAsB;AAAA,QACvF,UAAA,EAAY,kBAAA;AAAA,QACZ,QAAA,EAAU,UAAA;AAAA,QACV,IAAA,EAAM;AAAA,OACP,CAAA;AAED,MAAA,IAAI;AACF,QAAAC,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,MAAM,IAAA,GAAO,UAAU,UAAA,EAAY,IAAA;AAEnC,QAAA,IAAI,CAAC,IAAA,CAAK,0BAAA,CAA2B,SAAS,iBAAiB,CAAA,IAAK,CAAC,IAAA,EAAM;AACzE,UAAA;AAAA;AAGF,QAAA,KAAA,CAAM,IAAA,CAAK;AAAA,UACT,OAAA;AAAA,UACA,IAAA;AAAA;AAAA,UAEA,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,MAAM,IAAA,GAAO,UAAU,UAAA,EAAY,IAAA;AAEnC,QAAA,IAAI,CAAC,IAAA,CAAK,0BAAA,CAA2B,SAAS,iBAAiB,CAAA,IAAK,CAAC,IAAA,EAAM;AACzE,UAAA;AAAA;AAGF,QAAA,MAAM,OAAA,GAAUH,uBAAA,CAAO,GAAA,CAAI,IAAI,CAAA;AAC/B,QAAA,MAAM,WAAA,GAAc,QAAQ,WAAA,EAAY;AAExC,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,MAAM,OAAA,CAAQ,KAAA,EAAM,CAAE,GAAA,CAAI,GAAG,GAAG,CAAA;AAAA,cAChC,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,GAAA,CAAI,SAAA,CAAU,IAAI,CAAA;AACzC,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
  }
@@ -173,6 +176,66 @@ class InfraWalletClient {
173
176
  errors
174
177
  };
175
178
  }
179
+ // Helper method to check if database autoload should be used
180
+ shouldUseAutoloadFromDatabase(query, autoloadCostData) {
181
+ return query.tags === "()" && query.groups === "" && autoloadCostData && this.provider !== consts.CLOUD_PROVIDER.MOCK;
182
+ }
183
+ // Helper method to check if current month is included in the query
184
+ isCurrentMonthIncluded(query) {
185
+ const now = /* @__PURE__ */ new Date();
186
+ return query.granularity === consts.GRANULARITY.MONTHLY && parseInt(query.endTime, 10) >= new Date(now.getFullYear(), now.getMonth(), 1).getTime();
187
+ }
188
+ // Helper method to handle cached data retrieval
189
+ async handleCachedData(integrationName, query, results, forecasts) {
190
+ const cachedCosts = await functions.getReportsFromCache(this.cache, this.provider, integrationName, query);
191
+ if (!cachedCosts) {
192
+ return false;
193
+ }
194
+ this.logger.debug(`${this.provider}/${integrationName} costs from cache`);
195
+ cachedCosts.forEach((cost) => results.push(cost));
196
+ if (this.isCurrentMonthIncluded(query)) {
197
+ const cachedForecast = await functions.getForecastFromCache(this.cache, this.provider, integrationName, query);
198
+ if (cachedForecast !== void 0) {
199
+ this.logger.debug(`${this.provider}/${integrationName} forecast from cache: ${cachedForecast}`);
200
+ forecasts[this.provider] = cachedForecast;
201
+ }
202
+ }
203
+ return true;
204
+ }
205
+ // Helper method to process fresh data from API
206
+ async processFreshData(integrationConfig, integrationName, query, results, forecasts) {
207
+ const client = await this.initCloudClient(integrationConfig);
208
+ const costResponse = await this.fetchCosts(integrationConfig, client, query);
209
+ const transformedReports = await this.transformCostsData(integrationConfig, query, costResponse);
210
+ await functions.setReportsToCache(
211
+ this.cache,
212
+ transformedReports,
213
+ this.provider,
214
+ integrationName,
215
+ query,
216
+ functions.getDefaultCacheTTL(consts.CACHE_CATEGORY.COSTS, this.provider)
217
+ );
218
+ transformedReports.forEach((value) => results.push(value));
219
+ if (this.isCurrentMonthIncluded(query)) {
220
+ await this.handleForecastData(integrationConfig, integrationName, query, forecasts);
221
+ }
222
+ }
223
+ // Helper method to handle forecast data processing
224
+ async handleForecastData(integrationConfig, integrationName, query, forecasts) {
225
+ const integrationForecast = await this.fetchForecast(integrationConfig);
226
+ if (integrationForecast !== null && integrationForecast > 0) {
227
+ forecasts[this.provider] = integrationForecast;
228
+ await functions.setForecastToCache(
229
+ this.cache,
230
+ integrationForecast,
231
+ this.provider,
232
+ integrationName,
233
+ query,
234
+ functions.getDefaultCacheTTL(consts.CACHE_CATEGORY.COSTS, this.provider)
235
+ );
236
+ this.logger.debug(`${this.provider}/${integrationName} forecast cached: ${integrationForecast}`);
237
+ }
238
+ }
176
239
  async getCostReports(query) {
177
240
  const autoloadCostData = this.config.getOptionalBoolean("backend.infraWallet.autoload.enabled") ?? false;
178
241
  const integrationConfigs = this.config.getOptionalConfigArray(
@@ -182,40 +245,22 @@ class InfraWalletClient {
182
245
  return { reports: [], errors: [] };
183
246
  }
184
247
  const results = [];
248
+ const forecasts = {};
185
249
  const errors = [];
186
- if (query.tags === "()" && query.groups === "" && autoloadCostData && this.provider !== consts.CLOUD_PROVIDER.MOCK) {
250
+ if (this.shouldUseAutoloadFromDatabase(query, autoloadCostData)) {
187
251
  const reportsFromDatabase = await this.getCostReportsFromDatabase(query);
188
- reportsFromDatabase.forEach((report) => {
189
- results.push(report);
190
- });
252
+ reportsFromDatabase.forEach((report) => results.push(report));
191
253
  } else {
192
254
  const promises = [];
193
255
  for (const integrationConfig of integrationConfigs) {
194
256
  const integrationName = integrationConfig.getString("name");
195
- const cachedCosts = await functions.getReportsFromCache(this.cache, this.provider, integrationName, query);
196
- if (cachedCosts) {
197
- this.logger.debug(`${this.provider}/${integrationName} costs from cache`);
198
- cachedCosts.forEach((cost) => {
199
- results.push(cost);
200
- });
257
+ const foundCachedData = await this.handleCachedData(integrationName, query, results, forecasts);
258
+ if (foundCachedData) {
201
259
  continue;
202
260
  }
203
261
  const promise = (async () => {
204
262
  try {
205
- const client = await this.initCloudClient(integrationConfig);
206
- const costResponse = await this.fetchCosts(integrationConfig, client, query);
207
- const transformedReports = await this.transformCostsData(integrationConfig, query, costResponse);
208
- await functions.setReportsToCache(
209
- this.cache,
210
- transformedReports,
211
- this.provider,
212
- integrationName,
213
- query,
214
- functions.getDefaultCacheTTL(consts.CACHE_CATEGORY.COSTS, this.provider)
215
- );
216
- transformedReports.forEach((value) => {
217
- results.push(value);
218
- });
263
+ await this.processFreshData(integrationConfig, integrationName, query, results, forecasts);
219
264
  } catch (e) {
220
265
  this.logger.error(e);
221
266
  errors.push({
@@ -231,6 +276,7 @@ class InfraWalletClient {
231
276
  }
232
277
  return {
233
278
  reports: results,
279
+ forecasts,
234
280
  errors
235
281
  };
236
282
  }
@@ -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 getForecastFromCache,\n getReportsFromCache,\n getTagKeysFromCache,\n getTagValuesFromCache,\n logTransformationSummary,\n setForecastToCache,\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 // Helper method to check if database autoload should be used\n private shouldUseAutoloadFromDatabase(query: CostQuery, autoloadCostData: boolean): boolean {\n return query.tags === '()' && query.groups === '' && autoloadCostData && this.provider !== CLOUD_PROVIDER.MOCK;\n }\n\n // Helper method to check if current month is included in the query\n private isCurrentMonthIncluded(query: CostQuery): boolean {\n const now = new Date();\n return (\n query.granularity === GRANULARITY.MONTHLY &&\n parseInt(query.endTime, 10) >= new Date(now.getFullYear(), now.getMonth(), 1).getTime()\n );\n }\n\n // Helper method to handle cached data retrieval\n private async handleCachedData(\n integrationName: string,\n query: CostQuery,\n results: Report[],\n forecasts: Record<string, number>,\n ): Promise<boolean> {\n const cachedCosts = await getReportsFromCache(this.cache, this.provider, integrationName, query);\n if (!cachedCosts) {\n return false;\n }\n\n this.logger.debug(`${this.provider}/${integrationName} costs from cache`);\n cachedCosts.forEach(cost => results.push(cost));\n\n if (this.isCurrentMonthIncluded(query)) {\n const cachedForecast = await getForecastFromCache(this.cache, this.provider, integrationName, query);\n if (cachedForecast !== undefined) {\n this.logger.debug(`${this.provider}/${integrationName} forecast from cache: ${cachedForecast}`);\n forecasts[this.provider] = cachedForecast;\n }\n }\n return true;\n }\n\n // Helper method to process fresh data from API\n private async processFreshData(\n integrationConfig: Config,\n integrationName: string,\n query: CostQuery,\n results: Report[],\n forecasts: Record<string, number>,\n ): Promise<void> {\n const client = await this.initCloudClient(integrationConfig);\n const costResponse = await this.fetchCosts(integrationConfig, client, query);\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) => results.push(value));\n\n if (this.isCurrentMonthIncluded(query)) {\n await this.handleForecastData(integrationConfig, integrationName, query, forecasts);\n }\n }\n\n // Helper method to handle forecast data processing\n private async handleForecastData(\n integrationConfig: Config,\n integrationName: string,\n query: CostQuery,\n forecasts: Record<string, number>,\n ): Promise<void> {\n const integrationForecast = await this.fetchForecast(integrationConfig);\n if (integrationForecast !== null && integrationForecast > 0) {\n forecasts[this.provider] = integrationForecast;\n\n await setForecastToCache(\n this.cache,\n integrationForecast,\n this.provider,\n integrationName,\n query,\n getDefaultCacheTTL(CACHE_CATEGORY.COSTS, this.provider),\n );\n this.logger.debug(`${this.provider}/${integrationName} forecast cached: ${integrationForecast}`);\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\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 // Use autoload from database if conditions are met\n if (this.shouldUseAutoloadFromDatabase(query, autoloadCostData)) {\n const reportsFromDatabase = await this.getCostReportsFromDatabase(query);\n reportsFromDatabase.forEach(report => results.push(report));\n } else {\n const promises = [];\n\n for (const integrationConfig of integrationConfigs) {\n const integrationName = integrationConfig.getString('name');\n\n // Check for cached data first\n const foundCachedData = await this.handleCachedData(integrationName, query, results, forecasts);\n\n if (foundCachedData) {\n continue;\n }\n\n // Process fresh data from API\n const promise = (async () => {\n try {\n await this.processFreshData(integrationConfig, integrationName, query, results, forecasts);\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","CLOUD_PROVIDER","GRANULARITY","getReportsFromCache","getForecastFromCache","setReportsToCache","getDefaultCacheTTL","CACHE_CATEGORY","setForecastToCache","countCostItems","endOfMonth","startOfMonth","addMonths","NUMBER_OF_MONTHS_FETCHING_HISTORICAL_COSTS","bulkInsertCostItems","format","getWallet","getCostItems","reduce","PROVIDER_TYPE","usageDateToPeriodString"],"mappings":"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"}
@@ -76,6 +76,21 @@ async function getReportsFromCache(cache, provider, configKey, query) {
76
76
  const cachedCosts = await cache.get(cacheKey);
77
77
  return cachedCosts;
78
78
  }
79
+ async function getForecastFromCache(cache, provider, configKey, query) {
80
+ const cacheKey = [
81
+ "forecast",
82
+ provider,
83
+ configKey,
84
+ query.filters,
85
+ query.tags,
86
+ query.groups,
87
+ query.granularity,
88
+ query.startTime,
89
+ query.endTime
90
+ ].join("_");
91
+ const cachedForecast = await cache.get(cacheKey);
92
+ return cachedForecast;
93
+ }
79
94
  async function getMetricsFromCache(cache, provider, configKey, query) {
80
95
  const cacheKey = [
81
96
  provider,
@@ -125,6 +140,23 @@ async function setReportsToCache(cache, reports, provider, configKey, query, ttl
125
140
  ttl: ttl ?? 60 * 60 * 2 * 1e3
126
141
  });
127
142
  }
143
+ async function setForecastToCache(cache, forecast, provider, configKey, query, ttl) {
144
+ const cacheKey = [
145
+ "forecast",
146
+ provider,
147
+ configKey,
148
+ query.filters,
149
+ query.tags,
150
+ query.groups,
151
+ query.granularity,
152
+ query.startTime,
153
+ query.endTime
154
+ ].join("_");
155
+ await cache.set(cacheKey, forecast, {
156
+ ttl: ttl ?? 60 * 60 * 2 * 1e3
157
+ // cache for 2 hours by default, same as reports
158
+ });
159
+ }
128
160
  async function setMetricsToCache(cache, metrics, provider, configKey, query, ttl) {
129
161
  const cacheKey = [
130
162
  provider,
@@ -207,6 +239,7 @@ exports.getBillingPeriod = getBillingPeriod;
207
239
  exports.getBillingPeriodFormat = getBillingPeriodFormat;
208
240
  exports.getDailyPeriodStringsForOneMonth = getDailyPeriodStringsForOneMonth;
209
241
  exports.getDefaultCacheTTL = getDefaultCacheTTL;
242
+ exports.getForecastFromCache = getForecastFromCache;
210
243
  exports.getMetricsFromCache = getMetricsFromCache;
211
244
  exports.getReportsFromCache = getReportsFromCache;
212
245
  exports.getTagKeysFromCache = getTagKeysFromCache;
@@ -215,6 +248,7 @@ exports.logTransformationSummary = logTransformationSummary;
215
248
  exports.parseCost = parseCost;
216
249
  exports.parseFilters = parseFilters;
217
250
  exports.parseTags = parseTags;
251
+ exports.setForecastToCache = setForecastToCache;
218
252
  exports.setMetricsToCache = setMetricsToCache;
219
253
  exports.setReportsToCache = setReportsToCache;
220
254
  exports.setTagKeysToCache = setTagKeysToCache;
@@ -1 +1 @@
1
- {"version":3,"file":"functions.cjs.js","sources":["../../src/service/functions.ts"],"sourcesContent":["import { CacheService, LoggerService } from '@backstage/backend-plugin-api';\nimport { CACHE_CATEGORY, CLOUD_PROVIDER, DEFAULT_COSTS_CACHE_TTL, DEFAULT_TAGS_CACHE_TTL, GRANULARITY } from './consts';\nimport { CostQuery, Metric, MetricQuery, Report, Tag, TagsQuery, TransformationSummary } from './types';\nimport moment from 'moment';\n\n// In URL, tags are defined in this format:\n// tags=(provider1:key1=value1 OR provider2:key2=value2)\nexport function parseTags(tags: string): Tag[] {\n if (!tags.startsWith('(') || !tags.endsWith(')')) {\n return [];\n }\n\n const tagString = tags.slice(1, -1);\n if (!tagString) {\n return [];\n }\n\n const keyValuePairs = tagString.split(' OR ');\n return keyValuePairs.map(pair => {\n const [providerAndKey, value] = pair.split('=');\n const firstColonIndex = providerAndKey.indexOf(':');\n const provider = providerAndKey.slice(0, firstColonIndex);\n const key = providerAndKey.slice(firstColonIndex + 1);\n return { key: key, value: value, provider: provider };\n });\n}\n\n// convert Tag array to (provider1:key1=value1 OR provider2:key2=value2) format\nexport function tagsToString(tags: Tag[]): string {\n if (!tags || tags.length === 0) {\n return '()';\n }\n\n const keyValuePairs = tags.map(tag => `${tag.provider}:${tag.key}=${tag.value}`);\n return `(${keyValuePairs.join(' OR ')})`;\n}\n\n// check if targetTag exists in tags\nexport function tagExists(tags: Tag[], targetTag: Tag): boolean {\n return tags.some(\n tag => tag.provider === targetTag.provider && tag.key === targetTag.key && tag.value === targetTag.value,\n );\n}\n\nexport function getDefaultCacheTTL(cacheCategory: CACHE_CATEGORY, provider: CLOUD_PROVIDER): number {\n if (cacheCategory === CACHE_CATEGORY.TAGS) {\n return DEFAULT_TAGS_CACHE_TTL[provider];\n } else if (cacheCategory === CACHE_CATEGORY.COSTS) {\n return DEFAULT_COSTS_CACHE_TTL[provider];\n }\n\n return 0;\n}\n\nexport async function getTagKeysFromCache(\n cache: CacheService,\n provider: CLOUD_PROVIDER,\n configKey: string,\n query: TagsQuery,\n): Promise<Tag[] | undefined> {\n const cacheKey = [CACHE_CATEGORY.TAGS, 'tag-keys', provider, configKey, query.startTime, query.endTime].join('_');\n const data = (await cache.get(cacheKey)) as Tag[] | undefined;\n return data;\n}\n\nexport async function getTagValuesFromCache(\n cache: CacheService,\n provider: CLOUD_PROVIDER,\n configKey: string,\n tagKey: string,\n query: TagsQuery,\n): Promise<Tag[] | undefined> {\n const cacheKey = [\n CACHE_CATEGORY.TAGS,\n 'tag-values',\n provider,\n configKey,\n tagKey,\n query.startTime,\n query.endTime,\n ].join('_');\n const data = (await cache.get(cacheKey)) as Tag[] | undefined;\n return data;\n}\n\nexport async function getReportsFromCache(\n cache: CacheService,\n provider: string,\n configKey: string,\n query: CostQuery,\n): Promise<Report[] | undefined> {\n const cacheKey = [\n provider,\n configKey,\n query.filters,\n query.tags,\n query.groups,\n query.granularity,\n query.startTime,\n query.endTime,\n ].join('_');\n const cachedCosts = (await cache.get(cacheKey)) as Report[] | undefined;\n return cachedCosts;\n}\n\nexport async function getMetricsFromCache(\n cache: CacheService,\n provider: string,\n configKey: string,\n query: MetricQuery,\n): Promise<Metric[] | undefined> {\n const cacheKey = [\n provider,\n configKey,\n query.name,\n query.query,\n query.granularity,\n query.startTime,\n query.endTime,\n ].join('_');\n const crypto = require('crypto');\n const cachedMetrics = (await cache.get(crypto.createHash('md5').update(cacheKey).digest('hex'))) as\n | Metric[]\n | undefined;\n return cachedMetrics;\n}\n\nexport async function setTagKeysToCache(\n cache: CacheService,\n tags: Tag[],\n provider: CLOUD_PROVIDER,\n configKey: string,\n query: TagsQuery,\n ttl?: number,\n) {\n const cacheKey = [CACHE_CATEGORY.TAGS, 'tag-keys', provider, configKey, query.startTime, query.endTime].join('_');\n await cache.set(cacheKey, tags, {\n ttl: ttl ?? getDefaultCacheTTL(CACHE_CATEGORY.TAGS, provider),\n });\n}\n\nexport async function setTagValuesToCache(\n cache: CacheService,\n tags: Tag[],\n provider: CLOUD_PROVIDER,\n configKey: string,\n tagKey: string,\n query: TagsQuery,\n ttl?: number,\n) {\n const cacheKey = [\n CACHE_CATEGORY.TAGS,\n 'tag-values',\n provider,\n configKey,\n tagKey,\n query.startTime,\n query.endTime,\n ].join('_');\n await cache.set(cacheKey, tags, {\n ttl: ttl ?? getDefaultCacheTTL(CACHE_CATEGORY.TAGS, provider),\n });\n}\n\nexport async function setReportsToCache(\n cache: CacheService,\n reports: Report[],\n provider: string,\n configKey: string,\n query: CostQuery,\n ttl?: number,\n) {\n const cacheKey = [\n provider,\n configKey,\n query.filters,\n query.tags,\n query.groups,\n query.granularity,\n query.startTime,\n query.endTime,\n ].join('_');\n await cache.set(cacheKey, reports, {\n ttl: ttl ?? 60 * 60 * 2 * 1000,\n }); // cache for 2 hours by default\n}\n\nexport async function setMetricsToCache(\n cache: CacheService,\n metrics: Metric[],\n provider: string,\n configKey: string,\n query: MetricQuery,\n ttl?: number,\n) {\n const cacheKey = [\n provider,\n configKey,\n query.name,\n query.query,\n query.granularity,\n query.startTime,\n query.endTime,\n ].join('_');\n const crypto = require('crypto');\n await cache.set(crypto.createHash('md5').update(cacheKey).digest('hex'), metrics, {\n ttl: ttl ?? 60 * 60 * 2 * 1000,\n }); // cache for 2 hours by default\n}\n\nexport function parseFilters(filters: string): Record<string, string[]> {\n const result: Record<string, string[]> = {};\n\n if (!filters.startsWith('(') || !filters.endsWith(')')) {\n return result;\n }\n\n const filterString = filters.slice(1, -1);\n if (!filterString) {\n return result;\n }\n\n const keyValuePairs = filterString.split(',').map(pair => pair.trim());\n\n keyValuePairs.forEach(pair => {\n const [key, value] = pair.split(':').map(s => s.trim());\n if (key && value) {\n if (value.startsWith('(') && value.endsWith(')')) {\n // multiple values\n const values = value\n .slice(1, -1)\n .split('|')\n .map(v => v.trim());\n result[key] = values;\n } else {\n // single value\n result[key] = [value];\n }\n }\n });\n\n return result;\n}\n\n/**\n * Returns the date format string for a billing period based on granularity.\n */\nexport function getBillingPeriodFormat(granularity: GRANULARITY): string {\n if (granularity === GRANULARITY.MONTHLY) {\n return 'YYYY-MM';\n } else if (granularity === GRANULARITY.DAILY) {\n return 'YYYY-MM-DD';\n }\n throw new Error('Invalid granularity');\n}\n\n/**\n * Converts a source date string to a billing period string based on granularity and source format.\n */\nexport function getBillingPeriod(granularity: GRANULARITY, sourceDate: string, sourceFormat: string): string {\n return moment(sourceDate, sourceFormat, true).format(getBillingPeriodFormat(granularity));\n}\n\n/**\n * Parses a cost value and rounds to 2 decimal places.\n * Returns 0 if the value is not a valid number.\n */\nexport function parseCost(value: any): number {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? Math.round(parsed * 100) / 100 : 0;\n}\n\nexport function getDailyPeriodStringsForOneMonth(yyyymm: number): string[] {\n const dateOjb = moment(yyyymm.toString(), 'YYYYMM');\n const startOfMonth = moment(dateOjb).startOf('month');\n const endOfMonth = moment(dateOjb).endOf('month');\n const periods: string[] = [];\n\n for (let date = startOfMonth; date.isBefore(endOfMonth) || date.isSame(endOfMonth); date.add(1, 'day')) {\n periods.push(date.format('YYYY-MM-DD'));\n }\n\n return periods;\n}\n\nexport function usageDateToPeriodString(usageDate: number): string {\n // usageDate format: either yyyymm (monthly) or yyyymmdd (daily)\n // output format: yyyy-mm (monthly) or yyyy-mm-dd (daily)\n const usageDateStr = usageDate.toString();\n if (usageDateStr.length === 6) {\n // Monthly format\n return `${usageDateStr.slice(0, 4)}-${usageDateStr.slice(4, 6)}`;\n } else if (usageDateStr.length === 8) {\n // Daily format\n return `${usageDateStr.slice(0, 4)}-${usageDateStr.slice(4, 6)}-${usageDateStr.slice(6, 8)}`;\n }\n throw new Error('Invalid usageDate format');\n}\n\n/**\n * Logs a standardized transformation summary for cost client data processing.\n * This provides consistent logging across all cost providers.\n */\nexport function logTransformationSummary(\n logger: LoggerService,\n provider: string,\n summary: TransformationSummary,\n): void {\n logger.info(\n `${provider} transformation summary: processed=${summary.processed}, uniqueReports=${summary.uniqueReports}, zeroAmount=${summary.zeroAmount}, missingFields=${summary.missingFields}, invalidDate=${summary.invalidDate}, timeRange=${summary.timeRange}, totalRecords=${summary.totalRecords}`,\n );\n}\n"],"names":["CACHE_CATEGORY","DEFAULT_TAGS_CACHE_TTL","DEFAULT_COSTS_CACHE_TTL","GRANULARITY","moment"],"mappings":"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"}
1
+ {"version":3,"file":"functions.cjs.js","sources":["../../src/service/functions.ts"],"sourcesContent":["import { CacheService, LoggerService } from '@backstage/backend-plugin-api';\nimport { CACHE_CATEGORY, CLOUD_PROVIDER, DEFAULT_COSTS_CACHE_TTL, DEFAULT_TAGS_CACHE_TTL, GRANULARITY } from './consts';\nimport { CostQuery, Metric, MetricQuery, Report, Tag, TagsQuery, TransformationSummary } from './types';\nimport moment from 'moment';\n\n// In URL, tags are defined in this format:\n// tags=(provider1:key1=value1 OR provider2:key2=value2)\nexport function parseTags(tags: string): Tag[] {\n if (!tags.startsWith('(') || !tags.endsWith(')')) {\n return [];\n }\n\n const tagString = tags.slice(1, -1);\n if (!tagString) {\n return [];\n }\n\n const keyValuePairs = tagString.split(' OR ');\n return keyValuePairs.map(pair => {\n const [providerAndKey, value] = pair.split('=');\n const firstColonIndex = providerAndKey.indexOf(':');\n const provider = providerAndKey.slice(0, firstColonIndex);\n const key = providerAndKey.slice(firstColonIndex + 1);\n return { key: key, value: value, provider: provider };\n });\n}\n\n// convert Tag array to (provider1:key1=value1 OR provider2:key2=value2) format\nexport function tagsToString(tags: Tag[]): string {\n if (!tags || tags.length === 0) {\n return '()';\n }\n\n const keyValuePairs = tags.map(tag => `${tag.provider}:${tag.key}=${tag.value}`);\n return `(${keyValuePairs.join(' OR ')})`;\n}\n\n// check if targetTag exists in tags\nexport function tagExists(tags: Tag[], targetTag: Tag): boolean {\n return tags.some(\n tag => tag.provider === targetTag.provider && tag.key === targetTag.key && tag.value === targetTag.value,\n );\n}\n\nexport function getDefaultCacheTTL(cacheCategory: CACHE_CATEGORY, provider: CLOUD_PROVIDER): number {\n if (cacheCategory === CACHE_CATEGORY.TAGS) {\n return DEFAULT_TAGS_CACHE_TTL[provider];\n } else if (cacheCategory === CACHE_CATEGORY.COSTS) {\n return DEFAULT_COSTS_CACHE_TTL[provider];\n }\n\n return 0;\n}\n\nexport async function getTagKeysFromCache(\n cache: CacheService,\n provider: CLOUD_PROVIDER,\n configKey: string,\n query: TagsQuery,\n): Promise<Tag[] | undefined> {\n const cacheKey = [CACHE_CATEGORY.TAGS, 'tag-keys', provider, configKey, query.startTime, query.endTime].join('_');\n const data = (await cache.get(cacheKey)) as Tag[] | undefined;\n return data;\n}\n\nexport async function getTagValuesFromCache(\n cache: CacheService,\n provider: CLOUD_PROVIDER,\n configKey: string,\n tagKey: string,\n query: TagsQuery,\n): Promise<Tag[] | undefined> {\n const cacheKey = [\n CACHE_CATEGORY.TAGS,\n 'tag-values',\n provider,\n configKey,\n tagKey,\n query.startTime,\n query.endTime,\n ].join('_');\n const data = (await cache.get(cacheKey)) as Tag[] | undefined;\n return data;\n}\n\nexport async function getReportsFromCache(\n cache: CacheService,\n provider: string,\n configKey: string,\n query: CostQuery,\n): Promise<Report[] | undefined> {\n const cacheKey = [\n provider,\n configKey,\n query.filters,\n query.tags,\n query.groups,\n query.granularity,\n query.startTime,\n query.endTime,\n ].join('_');\n const cachedCosts = (await cache.get(cacheKey)) as Report[] | undefined;\n return cachedCosts;\n}\n\nexport async function getForecastFromCache(\n cache: CacheService,\n provider: string,\n configKey: string,\n query: CostQuery,\n): Promise<number | undefined> {\n const cacheKey = [\n 'forecast',\n provider,\n configKey,\n query.filters,\n query.tags,\n query.groups,\n query.granularity,\n query.startTime,\n query.endTime,\n ].join('_');\n const cachedForecast = (await cache.get(cacheKey)) as number | undefined;\n return cachedForecast;\n}\n\nexport async function getMetricsFromCache(\n cache: CacheService,\n provider: string,\n configKey: string,\n query: MetricQuery,\n): Promise<Metric[] | undefined> {\n const cacheKey = [\n provider,\n configKey,\n query.name,\n query.query,\n query.granularity,\n query.startTime,\n query.endTime,\n ].join('_');\n const crypto = require('crypto');\n const cachedMetrics = (await cache.get(crypto.createHash('md5').update(cacheKey).digest('hex'))) as\n | Metric[]\n | undefined;\n return cachedMetrics;\n}\n\nexport async function setTagKeysToCache(\n cache: CacheService,\n tags: Tag[],\n provider: CLOUD_PROVIDER,\n configKey: string,\n query: TagsQuery,\n ttl?: number,\n) {\n const cacheKey = [CACHE_CATEGORY.TAGS, 'tag-keys', provider, configKey, query.startTime, query.endTime].join('_');\n await cache.set(cacheKey, tags, {\n ttl: ttl ?? getDefaultCacheTTL(CACHE_CATEGORY.TAGS, provider),\n });\n}\n\nexport async function setTagValuesToCache(\n cache: CacheService,\n tags: Tag[],\n provider: CLOUD_PROVIDER,\n configKey: string,\n tagKey: string,\n query: TagsQuery,\n ttl?: number,\n) {\n const cacheKey = [\n CACHE_CATEGORY.TAGS,\n 'tag-values',\n provider,\n configKey,\n tagKey,\n query.startTime,\n query.endTime,\n ].join('_');\n await cache.set(cacheKey, tags, {\n ttl: ttl ?? getDefaultCacheTTL(CACHE_CATEGORY.TAGS, provider),\n });\n}\n\nexport async function setReportsToCache(\n cache: CacheService,\n reports: Report[],\n provider: string,\n configKey: string,\n query: CostQuery,\n ttl?: number,\n) {\n const cacheKey = [\n provider,\n configKey,\n query.filters,\n query.tags,\n query.groups,\n query.granularity,\n query.startTime,\n query.endTime,\n ].join('_');\n await cache.set(cacheKey, reports, {\n ttl: ttl ?? 60 * 60 * 2 * 1000,\n }); // cache for 2 hours by default\n}\n\nexport async function setForecastToCache(\n cache: CacheService,\n forecast: number,\n provider: string,\n configKey: string,\n query: CostQuery,\n ttl?: number,\n) {\n const cacheKey = [\n 'forecast',\n provider,\n configKey,\n query.filters,\n query.tags,\n query.groups,\n query.granularity,\n query.startTime,\n query.endTime,\n ].join('_');\n await cache.set(cacheKey, forecast, {\n ttl: ttl ?? 60 * 60 * 2 * 1000, // cache for 2 hours by default, same as reports\n });\n}\n\nexport async function setMetricsToCache(\n cache: CacheService,\n metrics: Metric[],\n provider: string,\n configKey: string,\n query: MetricQuery,\n ttl?: number,\n) {\n const cacheKey = [\n provider,\n configKey,\n query.name,\n query.query,\n query.granularity,\n query.startTime,\n query.endTime,\n ].join('_');\n const crypto = require('crypto');\n await cache.set(crypto.createHash('md5').update(cacheKey).digest('hex'), metrics, {\n ttl: ttl ?? 60 * 60 * 2 * 1000,\n }); // cache for 2 hours by default\n}\n\nexport function parseFilters(filters: string): Record<string, string[]> {\n const result: Record<string, string[]> = {};\n\n if (!filters.startsWith('(') || !filters.endsWith(')')) {\n return result;\n }\n\n const filterString = filters.slice(1, -1);\n if (!filterString) {\n return result;\n }\n\n const keyValuePairs = filterString.split(',').map(pair => pair.trim());\n\n keyValuePairs.forEach(pair => {\n const [key, value] = pair.split(':').map(s => s.trim());\n if (key && value) {\n if (value.startsWith('(') && value.endsWith(')')) {\n // multiple values\n const values = value\n .slice(1, -1)\n .split('|')\n .map(v => v.trim());\n result[key] = values;\n } else {\n // single value\n result[key] = [value];\n }\n }\n });\n\n return result;\n}\n\n/**\n * Returns the date format string for a billing period based on granularity.\n */\nexport function getBillingPeriodFormat(granularity: GRANULARITY): string {\n if (granularity === GRANULARITY.MONTHLY) {\n return 'YYYY-MM';\n } else if (granularity === GRANULARITY.DAILY) {\n return 'YYYY-MM-DD';\n }\n throw new Error('Invalid granularity');\n}\n\n/**\n * Converts a source date string to a billing period string based on granularity and source format.\n */\nexport function getBillingPeriod(granularity: GRANULARITY, sourceDate: string, sourceFormat: string): string {\n return moment(sourceDate, sourceFormat, true).format(getBillingPeriodFormat(granularity));\n}\n\n/**\n * Parses a cost value and rounds to 2 decimal places.\n * Returns 0 if the value is not a valid number.\n */\nexport function parseCost(value: any): number {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? Math.round(parsed * 100) / 100 : 0;\n}\n\nexport function getDailyPeriodStringsForOneMonth(yyyymm: number): string[] {\n const dateOjb = moment(yyyymm.toString(), 'YYYYMM');\n const startOfMonth = moment(dateOjb).startOf('month');\n const endOfMonth = moment(dateOjb).endOf('month');\n const periods: string[] = [];\n\n for (let date = startOfMonth; date.isBefore(endOfMonth) || date.isSame(endOfMonth); date.add(1, 'day')) {\n periods.push(date.format('YYYY-MM-DD'));\n }\n\n return periods;\n}\n\nexport function usageDateToPeriodString(usageDate: number): string {\n // usageDate format: either yyyymm (monthly) or yyyymmdd (daily)\n // output format: yyyy-mm (monthly) or yyyy-mm-dd (daily)\n const usageDateStr = usageDate.toString();\n if (usageDateStr.length === 6) {\n // Monthly format\n return `${usageDateStr.slice(0, 4)}-${usageDateStr.slice(4, 6)}`;\n } else if (usageDateStr.length === 8) {\n // Daily format\n return `${usageDateStr.slice(0, 4)}-${usageDateStr.slice(4, 6)}-${usageDateStr.slice(6, 8)}`;\n }\n throw new Error('Invalid usageDate format');\n}\n\n/**\n * Logs a standardized transformation summary for cost client data processing.\n * This provides consistent logging across all cost providers.\n */\nexport function logTransformationSummary(\n logger: LoggerService,\n provider: string,\n summary: TransformationSummary,\n): void {\n logger.info(\n `${provider} transformation summary: processed=${summary.processed}, uniqueReports=${summary.uniqueReports}, zeroAmount=${summary.zeroAmount}, missingFields=${summary.missingFields}, invalidDate=${summary.invalidDate}, timeRange=${summary.timeRange}, totalRecords=${summary.totalRecords}`,\n );\n}\n"],"names":["CACHE_CATEGORY","DEFAULT_TAGS_CACHE_TTL","DEFAULT_COSTS_CACHE_TTL","GRANULARITY","moment"],"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;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electrolux-oss/plugin-infrawallet-backend",
3
- "version": "1.1.0-20251218080407-fbaf733",
3
+ "version": "1.1.0-20260115072024-d6f33e2",
4
4
  "backstage": {
5
5
  "role": "backend-plugin",
6
6
  "pluginId": "infrawallet",