@electrolux-oss/plugin-infrawallet-backend 0.1.3 → 0.1.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/service/functions.ts","../src/service/AwsClient.ts","../src/service/AzureClient.ts","../src/service/GCPClient.ts","../src/service/router.ts","../src/plugin.ts"],"sourcesContent":["import { DatabaseService } from '@backstage/backend-plugin-api';\nimport { CategoryMapping } from './types';\n\nexport async function getCategoryMappings(\n database: DatabaseService,\n provider: string,\n): Promise<{ [category: string]: string[] }> {\n const result: { [category: string]: string[] } = {};\n const client = await database.getClient();\n const mappings = await client\n .where({ provider: provider })\n .select()\n .from<CategoryMapping>('category_mappings');\n mappings.forEach(mapping => {\n if (typeof mapping.cloud_service_names === 'string') {\n // just in case if the database such as sqlite does not support JSON column\n result[mapping.category] = JSON.parse(mapping.cloud_service_names);\n } else {\n result[mapping.category] = mapping.cloud_service_names;\n }\n });\n return result;\n}\n\nexport function getCategoryByServiceName(\n serviceName: string,\n categoryMappings: { [category: string]: string[] },\n): string {\n for (const key of Object.keys(categoryMappings)) {\n const serviceNames = categoryMappings[key];\n if (serviceNames && serviceNames.includes(serviceName)) {\n return key;\n }\n }\n\n return 'Uncategorized';\n}\n","import {\n CostExplorerClient,\n GetCostAndUsageCommand,\n GetCostAndUsageCommandInput,\n Granularity,\n} from '@aws-sdk/client-cost-explorer';\nimport { AssumeRoleCommand, STSClient } from '@aws-sdk/client-sts';\nimport { LoggerService, DatabaseService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport { CostQuery, Report } from './types';\nimport { getCategoryMappings, getCategoryByServiceName } from './functions';\n\nexport class AwsClient implements InfraWalletApi {\n static create(\n config: Config,\n database: DatabaseService,\n logger: LoggerService,\n ) {\n return new AwsClient(config, database, logger);\n }\n\n constructor(\n private readonly config: Config,\n private readonly database: DatabaseService,\n private readonly logger: LoggerService,\n ) {\n }\n\n convertServiceName(serviceName: string): string {\n let convertedName = serviceName;\n\n const prefixes = ['Amazon', 'AWS'];\n\n const aliases = new Map<string, string>([\n ['Elastic Compute Cloud - Compute', 'EC2 - Instances'],\n ['Virtual Private Cloud', 'VPC (Virtual Private Cloud)'],\n ['Relational Database Service', 'RDS (Relational Database Service)'],\n ['Simple Storage Service', 'S3 (Simple Storage Service)'],\n [\n 'Managed Streaming for Apache Kafka',\n 'MSK (Managed Streaming for Apache Kafka)',\n ],\n [\n 'Elastic Container Service for Kubernetes',\n 'EKS (Elastic Container Service for Kubernetes)',\n ],\n ['Simple Queue Service', 'SQS (Simple Queue Service)'],\n ['Simple Notification Service', 'SNS (Simple Notification Service)'],\n ]);\n\n for (const prefix of prefixes) {\n if (serviceName.startsWith(prefix)) {\n convertedName = serviceName.slice(prefix.length).trim();\n }\n }\n\n if (aliases.has(convertedName)) {\n convertedName = aliases.get(convertedName) || convertedName;\n }\n\n return `AWS/${convertedName}`;\n }\n\n async fetchCostsFromCloud(query: CostQuery): Promise<Report[]> {\n const conf = this.config.getOptionalConfigArray(\n 'backend.infraWallet.integrations.aws',\n );\n if (!conf) {\n return [];\n }\n\n const promises = [];\n const results: Report[] = [];\n const groupPairs = [];\n query.groups.split(',').forEach(group => {\n if (group.includes(':')) {\n const [type, name] = group.split(':');\n groupPairs.push({ type, name });\n }\n });\n\n for (const c of conf) {\n const name = c.getString('name');\n const accountId = c.getString('accountId');\n const assumedRoleName = c.getString('assumedRoleName');\n const accessKeyId = c.getOptionalString('accessKeyId');\n const accessKeySecret = c.getOptionalString('accessKeySecret');\n const tags = c.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 const categoryMappings = await getCategoryMappings(this.database, 'aws');\n\n let stsParams = {};\n if (accessKeyId && accessKeySecret) {\n stsParams = {\n region: 'us-east-1',\n credentials: {\n accessKeyId: accessKeyId as string,\n secretAccessKey: accessKeySecret as string,\n },\n };\n } else {\n stsParams = {\n region: 'us-east-1',\n };\n }\n const promise = (async () => {\n try {\n const client = new STSClient(stsParams);\n const commandInput = {\n // AssumeRoleRequest\n RoleArn: `arn:aws:iam::${accountId}:role/${assumedRoleName}`,\n RoleSessionName: 'AssumeRoleSession1',\n };\n const assumeRoleCommand = new AssumeRoleCommand(commandInput);\n const assumeRoleResponse = await client.send(assumeRoleCommand);\n // init aws cost explorer client\n const awsCeClient = new CostExplorerClient({\n region: 'us-east-1',\n credentials: {\n accessKeyId: assumeRoleResponse.Credentials\n ?.AccessKeyId as string,\n secretAccessKey: assumeRoleResponse.Credentials\n ?.SecretAccessKey as string,\n sessionToken: assumeRoleResponse.Credentials\n ?.SessionToken as string,\n },\n });\n\n // query this aws account's cost and usage using @aws-sdk/client-cost-explorer\n let costAndUsageResults: any[] = [];\n let nextPageToken = undefined;\n\n do {\n const input: GetCostAndUsageCommandInput = {\n TimePeriod: {\n Start: moment(parseInt(query.startTime, 10)).format('YYYY-MM-DD'),\n End: moment(parseInt(query.endTime, 10)).format('YYYY-MM-DD'),\n },\n Granularity: query.granularity.toUpperCase() as Granularity,\n Filter: { Dimensions: { Key: 'RECORD_TYPE', Values: ['Usage'] } },\n GroupBy: [{ Type: 'DIMENSION', Key: 'SERVICE' }],\n Metrics: ['UnblendedCost'],\n NextPageToken: nextPageToken,\n };\n\n const getCostCommand = new GetCostAndUsageCommand(input);\n const costAndUsageResponse = await awsCeClient.send(getCostCommand);\n\n costAndUsageResults = costAndUsageResults.concat(costAndUsageResponse.ResultsByTime);\n nextPageToken = costAndUsageResponse.NextPageToken;\n } while (nextPageToken);\n\n const transformedData = reduce(\n costAndUsageResults,\n (accumulator: { [key: string]: Report }, row) => {\n const rowTime = row.TimePeriod?.Start;\n let period = 'unknown';\n if (rowTime) {\n if (query.granularity.toUpperCase() === 'MONTHLY') {\n period = rowTime.substring(0, 7);\n } else {\n period = rowTime;\n }\n }\n if (row.Groups) {\n row.Groups.forEach((group: any) => {\n const serviceName = group.Keys ? group.Keys[0] : '';\n const keyName = `${name}_${serviceName}`;\n\n if (!accumulator[keyName]) {\n accumulator[keyName] = {\n id: keyName,\n name: `AWS/${name}`,\n service: this.convertServiceName(serviceName),\n category: getCategoryByServiceName(\n serviceName,\n categoryMappings,\n ),\n provider: 'AWS',\n reports: {},\n ...tagKeyValues,\n };\n }\n\n const groupMetrics = group.Metrics;\n\n if (groupMetrics !== undefined) {\n accumulator[keyName].reports[period] = parseFloat(\n groupMetrics.UnblendedCost.Amount ?? '0.0',\n );\n }\n });\n }\n\n return accumulator;\n },\n {},\n );\n\n Object.values(transformedData).map((value: any) => {\n results.push(value);\n });\n } catch (e) {\n this.logger.error(e);\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n return results;\n }\n}\n","import { CostManagementClient, QueryDefinition } from '@azure/arm-costmanagement';\nimport { ClientSecretCredential } from '@azure/identity';\nimport { createHttpHeaders, createPipelineRequest } from \"@azure/core-rest-pipeline\";\nimport { LoggerService, DatabaseService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport { CostQuery, Report } from './types';\nimport { getCategoryMappings, getCategoryByServiceName } from './functions';\n\nexport class AzureClient implements InfraWalletApi {\n static create(config: Config, database: DatabaseService, logger: LoggerService) {\n return new AzureClient(config, database, logger);\n }\n\n constructor(\n private readonly config: Config,\n private readonly database: DatabaseService,\n private readonly logger: LoggerService,\n ) {\n }\n\n convertServiceName(serviceName: string): string {\n let convertedName = serviceName;\n\n const prefixes = ['Azure'];\n\n for (const prefix of prefixes) {\n if (serviceName.startsWith(prefix)) {\n convertedName = serviceName.slice(prefix.length).trim();\n }\n }\n\n return `Azure/${convertedName}`;\n }\n\n formatDate(dateNumber: number): string | null {\n // dateNumber example: 20240407\n const dateString = dateNumber.toString();\n\n if (dateString.length !== 8) {\n return null;\n }\n\n const year = dateString.slice(0, 4);\n const month = dateString.slice(4, 6);\n const day = dateString.slice(6);\n\n return `${year}-${month}-${day}`;\n }\n\n async fetchDataWithRetry(\n client: CostManagementClient,\n url: string,\n body: any,\n maxRetries = 5\n ): Promise<any> {\n let retries = 0;\n\n while (retries < maxRetries) {\n const request = createPipelineRequest({\n url: url,\n method: \"POST\",\n body: JSON.stringify(body),\n headers: createHttpHeaders({\n \"Content-Type\": \"application/json\"\n }),\n });\n const response = await client.pipeline.sendRequest(client, request);\n if (response.status === 200) {\n return JSON.parse(response.bodyAsText || '{}');\n }\n else if (response.status === 429) {\n const retryAfter = parseInt(response.headers.get(\"x-ms-ratelimit-microsoft.costmanagement-entity-retry-after\") || '60', 10);\n this.logger.warn(`Hit Azure rate limit, retrying after ${retryAfter} seconds...`);\n await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));\n retries++;\n } else {\n throw new Error(response.bodyAsText as string);\n }\n }\n\n throw new Error('Max retries exceeded');\n }\n\n async queryAzureCostExplorer(\n azureClient: CostManagementClient,\n subscription: string,\n granularity: string,\n groups: { type: string; name: string }[],\n startDate: moment.Moment,\n endDate: moment.Moment,\n ) {\n // Azure SDK doesn't support pagination, so sending HTTP request directly\n const url = `https://management.azure.com/subscriptions/${subscription}/providers/Microsoft.CostManagement/query?api-version=2022-10-01`;\n\n const query: QueryDefinition = {\n type: 'ActualCost',\n dataset: {\n granularity: granularity,\n aggregation: { totalCostUSD: { name: 'CostUSD', function: 'Sum' } },\n grouping: groups,\n },\n timeframe: 'Custom',\n timePeriod: {\n from: startDate.toDate(),\n to: endDate.toDate(),\n },\n };\n\n let result = await this.fetchDataWithRetry(azureClient, url, query);\n let allResults = result.properties.rows;\n\n while (result.properties.nextLink) {\n result = await this.fetchDataWithRetry(azureClient, result.properties.nextLink, query);\n allResults = allResults.concat(result.properties.rows);\n }\n\n return allResults;\n }\n\n async fetchCostsFromCloud(query: CostQuery): Promise<Report[]> {\n const conf = this.config.getOptionalConfigArray(\n 'backend.infraWallet.integrations.azure',\n );\n if (!conf) {\n return [];\n }\n\n const categoryMappings = await getCategoryMappings(\n this.database,\n 'azure',\n );\n\n const promises = [];\n const results: Report[] = [];\n\n const groupPairs = [{ type: 'Dimension', name: 'ServiceName' }];\n for (const c of conf) {\n const name = c.getString('name');\n const subscriptionId = c.getString('subscriptionId');\n const tenantId = c.getString('tenantId');\n const clientId = c.getString('clientId');\n const clientSecret = c.getString('clientSecret');\n const credential = new ClientSecretCredential(\n tenantId as string,\n clientId as string,\n clientSecret as string,\n );\n const client = new CostManagementClient(credential);\n const tags = c.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 const promise = (async () => {\n try {\n const costResponse = await this.queryAzureCostExplorer(\n client,\n subscriptionId as string,\n query.granularity,\n groupPairs,\n moment(parseInt(query.startTime, 10)),\n moment(parseInt(query.endTime, 10)),\n );\n\n /* \n Monthly cost sample:\n [\n 123.456,\n \"2024-04-07T00:00:00\", // BillingMonth\n \"Azure App Service\",\n \"EUR\"\n ]\n \n Daily cost sample:\n [\n 12.3456,\n 20240407, // UsageDate\n \"Azure App Service\",\n \"EUR\"\n ]\n */\n const transformedData = reduce(\n costResponse,\n (accumulator: { [key: string]: Report }, row) => {\n const cost = row[0];\n let date = row[1];\n const serviceName = row[2];\n\n if (query.granularity.toUpperCase() === 'DAILY') {\n // 20240407 -> \"2024-04-07\"\n date = this.formatDate(date);\n }\n\n let keyName = name;\n for (let i = 0; i < groupPairs.length; i++) {\n keyName += `->${row[i + 2]}`;\n }\n\n if (!accumulator[keyName]) {\n accumulator[keyName] = {\n id: keyName,\n name: `Azure/${name}`,\n service: this.convertServiceName(serviceName),\n category: getCategoryByServiceName(serviceName, categoryMappings),\n provider: 'Azure',\n reports: {},\n ...tagKeyValues,\n };\n }\n\n if (\n !moment(date).isBefore(moment(parseInt(query.startTime, 10)))\n ) {\n if (query.granularity.toUpperCase() === 'MONTHLY') {\n const yearMonth = date.substring(0, 7);\n accumulator[keyName].reports[yearMonth] = parseFloat(cost);\n } else {\n accumulator[keyName].reports[date] = parseFloat(cost);\n }\n }\n return accumulator;\n },\n {},\n );\n\n Object.values(transformedData).map((value: Report) => {\n results.push(value);\n });\n } catch (e) {\n this.logger.error(e);\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n return results;\n }\n}\n","import { LoggerService, DatabaseService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { BigQuery } from '@google-cloud/bigquery';\nimport { reduce } from 'lodash';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport { CostQuery, Report } from './types';\nimport { getCategoryByServiceName, getCategoryMappings } from './functions';\n\nexport class GCPClient implements InfraWalletApi {\n static create(\n config: Config,\n database: DatabaseService,\n logger: LoggerService,\n ) {\n return new GCPClient(config, database, logger);\n }\n\n constructor(\n private readonly config: Config,\n private readonly database: DatabaseService,\n private readonly logger: LoggerService,\n ) {}\n\n convertServiceName(serviceName: string): string {\n let convertedName = serviceName;\n\n const prefixes = ['GCP'];\n\n for (const prefix of prefixes) {\n if (serviceName.startsWith(prefix)) {\n convertedName = serviceName.slice(prefix.length).trim();\n }\n }\n\n return `GCP/${convertedName}`;\n }\n\n async queryBigQuery(\n keyFilePath: string,\n projectId: string,\n datasetId: string,\n tableId: string,\n query: CostQuery,\n ) {\n // Configure a JWT auth client\n const options = {\n keyFilename: keyFilePath,\n projectId: projectId,\n };\n\n // Initialize the BigQuery API\n const bigquery = new BigQuery(options);\n try {\n const periodFormat = query.granularity.toUpperCase() === 'MONTHLY' ? '%Y-%m' : '%Y-%m-%d';\n const sql = `\n SELECT\n project.name AS project,\n service.description AS service,\n FORMAT_TIMESTAMP('${periodFormat}', usage_start_time) AS period,\n SUM(cost) AS total_cost\n FROM\n \\`${projectId}.${datasetId}.${tableId}\\`\n WHERE\n project.name IS NOT NULL\n AND cost > 0\n AND usage_start_time >= TIMESTAMP_MILLIS(${query.startTime})\n AND usage_start_time <= TIMESTAMP_MILLIS(${query.endTime})\n GROUP BY\n project, service, period\n ORDER BY\n project, period, total_cost DESC`;\n\n // Run the query as a job\n const [job] = await bigquery.createQueryJob({\n query: sql,\n location: 'US',\n });\n\n // Wait for the query to finish\n const [rows] = await job.getQueryResults();\n\n return rows;\n } catch (err) {\n throw new Error(err.message);\n }\n }\n\n async fetchCostsFromCloud(query: CostQuery): Promise<Report[]> {\n const conf = this.config.getOptionalConfigArray(\n 'backend.infraWallet.integrations.gcp',\n );\n if (!conf) {\n return [];\n }\n\n const promises = [];\n const results: Report[] = [];\n\n for (const c of conf) {\n const name = c.getString('name');\n const keyFilePath = c.getString('keyFilePath');\n const projectId = c.getString('projectId');\n const datasetId = c.getString('datasetId');\n const tableId = c.getString('tableId');\n const tags = c.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 const categoryMappings = await getCategoryMappings(this.database, 'gcp');\n\n const promise = (async () => {\n try {\n const costResponse = await this.queryBigQuery(\n keyFilePath,\n projectId,\n datasetId,\n tableId,\n query,\n );\n const transformedData = reduce(\n costResponse,\n (acc: { [key: string]: Report }, row) => {\n const period = row.period;\n const keyName = `${name}_${row.project}_${row.service}`;\n\n if (!acc[keyName]) {\n acc[keyName] = {\n id: keyName,\n name: `GCP/${name}`,\n service: this.convertServiceName(row.service),\n category: getCategoryByServiceName(\n row.service,\n categoryMappings,\n ),\n provider: 'GCP',\n reports: {},\n ...{ project: row.project }, // TODO: how should we handle the project field? for now, we add project name as a field in the report\n ...tagKeyValues, // note that if there is a tag `project:foo` in config, it overrides the project field set above\n };\n }\n\n acc[keyName].reports[period] = row.total_cost;\n\n return acc;\n },\n {},\n );\n\n Object.values(transformedData).map((value: any) => {\n results.push(value);\n });\n } catch (e) {\n this.logger.error(e);\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n return results;\n }\n}\n","import { errorHandler } from '@backstage/backend-common';\nimport {\n CacheService,\n DatabaseService,\n LoggerService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { AwsClient } from './AwsClient';\nimport { AzureClient } from './AzureClient';\nimport { GCPClient } from './GCPClient';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport { Report } from './types';\n\nexport interface RouterOptions {\n logger: LoggerService;\n config: Config;\n cache: CacheService;\n database: DatabaseService;\n}\n\nasync function setUpDatabase(database: DatabaseService) {\n // check database migrations\n const client = await database.getClient();\n const migrationsDir = resolvePackagePath(\n '@electrolux-oss/plugin-infrawallet-backend',\n 'migrations',\n );\n if (!database.migrations?.skip) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n // if there are no category mappings, seed the database\n const category_mappings_count = await client('category_mappings').count(\n 'id as c',\n );\n if (\n category_mappings_count[0].c === 0 ||\n category_mappings_count[0].c === '0'\n ) {\n const seedsDir = resolvePackagePath(\n '@electrolux-oss/plugin-infrawallet-backend',\n 'seeds',\n );\n await client.seed.run({ directory: seedsDir });\n }\n}\n\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { logger, config, cache, database } = options;\n // do database migrations here to support the legacy backend system\n await setUpDatabase(database);\n\n const router = Router();\n router.use(express.json());\n\n const azureClient = AzureClient.create(config, database, logger);\n const awsClient = AwsClient.create(config, database, logger);\n const gcpClient = GCPClient.create(config, database, logger);\n const cloudClients: InfraWalletApi[] = [azureClient, awsClient, gcpClient];\n\n router.get('/health', (_, response) => {\n logger.info('PONG!');\n response.json({ status: 'ok' });\n });\n\n router.get('/reports', async (request, response) => {\n const filters = request.query.filters as string;\n const groups = request.query.groups as string;\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: Report[] = [];\n\n cloudClients.forEach(async client => {\n const fetchCloudCosts = (async () => {\n const cacheKey = [\n client.constructor.name,\n filters,\n groups,\n granularity,\n startTime,\n endTime,\n ].join('_');\n const cachedCosts = (await cache.get(cacheKey)) as Report[] | undefined;\n if (cachedCosts) {\n logger.debug(`${client.constructor.name} costs from cache`);\n cachedCosts.forEach(cost => {\n results.push(cost);\n });\n } else {\n try {\n const costs = await client.fetchCostsFromCloud({\n filters: filters,\n groups: groups,\n granularity: granularity,\n startTime: startTime,\n endTime: endTime,\n });\n await cache.set(cacheKey, costs, {\n ttl: 60 * 60 * 2 * 1000,\n }); // cache for 2 hours\n costs.forEach(cost => {\n results.push(cost);\n });\n } catch (e) {\n logger.error(e);\n }\n }\n })();\n promises.push(fetchCloudCosts);\n });\n\n await Promise.all(promises);\n\n response.json({ data: results, status: 'ok' });\n });\n\n router.use(errorHandler());\n return router;\n}\n","import {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * infraWalletPlugin backend plugin\n *\n * @public\n */\nexport const infraWalletPlugin = createBackendPlugin({\n pluginId: 'infrawallet',\n register(env) {\n env.registerInit({\n deps: {\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n cache: coreServices.cache,\n database: coreServices.database,\n },\n async init({ httpRouter, logger, config, cache, database }) {\n httpRouter.use(\n await createRouter({\n logger,\n config,\n cache,\n database,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n },\n });\n },\n});\n"],"names":["STSClient","AssumeRoleCommand","CostExplorerClient","moment","GetCostAndUsageCommand","reduce","_a","createPipelineRequest","createHttpHeaders","ClientSecretCredential","CostManagementClient","bigquery","BigQuery","resolvePackagePath","Router","express","errorHandler","createBackendPlugin","coreServices"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/service/functions.ts","../src/service/AwsClient.ts","../src/service/AzureClient.ts","../src/service/GCPClient.ts","../src/service/router.ts","../src/plugin.ts"],"sourcesContent":["import { CacheService, DatabaseService } from '@backstage/backend-plugin-api';\nimport { CategoryMapping, CostQuery, Report } from './types';\n\nexport async function getCategoryMappings(\n database: DatabaseService,\n provider: string,\n): Promise<{ [service: string]: string }> {\n const result: { [service: string]: string } = {};\n const client = await database.getClient();\n const default_mappings = await client\n .where({ provider: provider.toLowerCase() })\n .select()\n .from<CategoryMapping>('category_mappings_default');\n default_mappings.forEach(mapping => {\n if (typeof mapping.cloud_service_names === 'string') {\n // just in case if the database such as sqlite does not support JSON column\n JSON.parse(mapping.cloud_service_names).forEach((service: string) => {\n result[service] = mapping.category;\n });\n } else {\n mapping.cloud_service_names.forEach((service: string) => {\n result[service] = mapping.category;\n });\n }\n });\n\n // check if there are any records defined by user\n const override_mappings = await client\n .where({ provider: provider })\n .select()\n .from<CategoryMapping>('category_mappings_override');\n override_mappings.forEach(mapping => {\n if (typeof mapping.cloud_service_names === 'string') {\n // just in case if the database such as sqlite does not support JSON column\n JSON.parse(mapping.cloud_service_names).forEach((service: string) => {\n result[service] = mapping.category;\n });\n } else {\n mapping.cloud_service_names.forEach((service: string) => {\n result[service] = mapping.category;\n });\n }\n });\n\n return result;\n}\n\nexport function getCategoryByServiceName(serviceName: string, categoryMappings: { [service: string]: string }): string {\n if (serviceName in categoryMappings) {\n return categoryMappings[serviceName];\n }\n\n return 'Uncategorized';\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.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 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.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","import {\n CostExplorerClient,\n GetCostAndUsageCommand,\n GetCostAndUsageCommandInput,\n Granularity,\n} from '@aws-sdk/client-cost-explorer';\nimport { AssumeRoleCommand, STSClient } from '@aws-sdk/client-sts';\nimport { CacheService, DatabaseService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport { getCategoryByServiceName, getCategoryMappings, getReportsFromCache, setReportsToCache } from './functions';\nimport { ClientResponse, CloudProviderError, CostQuery, Report } from './types';\n\nexport class AwsClient implements InfraWalletApi {\n static create(config: Config, database: DatabaseService, cache: CacheService, logger: LoggerService) {\n return new AwsClient('AWS', config, database, cache, logger);\n }\n\n constructor(\n private readonly providerName: string,\n private readonly config: Config,\n private readonly database: DatabaseService,\n private readonly cache: CacheService,\n private readonly logger: LoggerService,\n ) {}\n\n convertServiceName(serviceName: string): string {\n let convertedName = serviceName;\n\n const prefixes = ['Amazon', 'AWS'];\n\n const aliases = new Map<string, string>([\n ['Elastic Compute Cloud - Compute', 'EC2 - Instances'],\n ['Virtual Private Cloud', 'VPC (Virtual Private Cloud)'],\n ['Relational Database Service', 'RDS (Relational Database Service)'],\n ['Simple Storage Service', 'S3 (Simple Storage Service)'],\n ['Managed Streaming for Apache Kafka', 'MSK (Managed Streaming for Apache Kafka)'],\n ['Elastic Container Service for Kubernetes', 'EKS (Elastic Container Service for Kubernetes)'],\n ['Elastic Container Service', 'ECS (Elastic Container Service)'],\n ['EC2 Container Registry (ECR)', 'ECR (Elastic Container Registry)'],\n ['Simple Queue Service', 'SQS (Simple Queue Service)'],\n ['Simple Notification Service', 'SNS (Simple Notification Service)'],\n ['Database Migration Service', 'DMS (Database Migration Service)'],\n ]);\n\n for (const prefix of prefixes) {\n if (serviceName.startsWith(prefix)) {\n convertedName = serviceName.slice(prefix.length).trim();\n }\n }\n\n if (aliases.has(convertedName)) {\n convertedName = aliases.get(convertedName) || convertedName;\n }\n\n return `${this.providerName}/${convertedName}`;\n }\n\n async fetchCostsFromCloud(query: CostQuery): Promise<ClientResponse> {\n const conf = this.config.getOptionalConfigArray('backend.infraWallet.integrations.aws');\n if (!conf) {\n return { reports: [], errors: [] };\n }\n\n const promises = [];\n const results: Report[] = [];\n const errors: CloudProviderError[] = [];\n const groupPairs = [];\n query.groups.split(',').forEach(group => {\n if (group.includes(':')) {\n const [type, name] = group.split(':');\n groupPairs.push({ type, name });\n }\n });\n\n for (const c of conf) {\n const accountName = c.getString('name');\n\n // first check if there is any cached\n const cachedCosts = await getReportsFromCache(this.cache, this.providerName, accountName, query);\n if (cachedCosts) {\n this.logger.debug(`${this.providerName}/${accountName} costs from cache`);\n cachedCosts.map(cost => {\n results.push(cost);\n });\n continue;\n }\n\n const accountId = c.getString('accountId');\n const assumedRoleName = c.getString('assumedRoleName');\n const accessKeyId = c.getOptionalString('accessKeyId');\n const accessKeySecret = c.getOptionalString('accessKeySecret');\n const tags = c.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 const categoryMappings = await getCategoryMappings(this.database, this.providerName);\n\n let stsParams = {};\n if (accessKeyId && accessKeySecret) {\n stsParams = {\n region: 'us-east-1',\n credentials: {\n accessKeyId: accessKeyId as string,\n secretAccessKey: accessKeySecret as string,\n },\n };\n } else {\n stsParams = {\n region: 'us-east-1',\n };\n }\n const promise = (async () => {\n try {\n const client = new STSClient(stsParams);\n const commandInput = {\n // AssumeRoleRequest\n RoleArn: `arn:aws:iam::${accountId}:role/${assumedRoleName}`,\n RoleSessionName: 'AssumeRoleSession1',\n };\n const assumeRoleCommand = new AssumeRoleCommand(commandInput);\n const assumeRoleResponse = await client.send(assumeRoleCommand);\n // init aws cost explorer client\n const awsCeClient = new CostExplorerClient({\n region: 'us-east-1',\n credentials: {\n accessKeyId: assumeRoleResponse.Credentials?.AccessKeyId as string,\n secretAccessKey: assumeRoleResponse.Credentials?.SecretAccessKey as string,\n sessionToken: assumeRoleResponse.Credentials?.SessionToken as string,\n },\n });\n\n // query this aws account's cost and usage using @aws-sdk/client-cost-explorer\n let costAndUsageResults: any[] = [];\n let nextPageToken = undefined;\n\n do {\n const input: GetCostAndUsageCommandInput = {\n TimePeriod: {\n Start: moment(parseInt(query.startTime, 10)).format('YYYY-MM-DD'),\n End: moment(parseInt(query.endTime, 10)).format('YYYY-MM-DD'),\n },\n Granularity: query.granularity.toUpperCase() as Granularity,\n Filter: { Dimensions: { Key: 'RECORD_TYPE', Values: ['Usage'] } },\n GroupBy: [{ Type: 'DIMENSION', Key: 'SERVICE' }],\n Metrics: ['UnblendedCost'],\n NextPageToken: nextPageToken,\n };\n\n const getCostCommand = new GetCostAndUsageCommand(input);\n const costAndUsageResponse = await awsCeClient.send(getCostCommand);\n\n costAndUsageResults = costAndUsageResults.concat(costAndUsageResponse.ResultsByTime);\n nextPageToken = costAndUsageResponse.NextPageToken;\n } while (nextPageToken);\n\n const transformedData = reduce(\n costAndUsageResults,\n (accumulator: { [key: string]: Report }, row) => {\n const rowTime = row.TimePeriod?.Start;\n let period = 'unknown';\n if (rowTime) {\n if (query.granularity.toUpperCase() === 'MONTHLY') {\n period = rowTime.substring(0, 7);\n } else {\n period = rowTime;\n }\n }\n if (row.Groups) {\n row.Groups.forEach((group: any) => {\n const serviceName = group.Keys ? group.Keys[0] : '';\n const keyName = `${accountName}_${serviceName}`;\n\n if (!accumulator[keyName]) {\n accumulator[keyName] = {\n id: keyName,\n name: `${this.providerName}/${accountName}`,\n service: this.convertServiceName(serviceName),\n category: getCategoryByServiceName(serviceName, categoryMappings),\n provider: this.providerName,\n reports: {},\n ...tagKeyValues,\n };\n }\n\n const groupMetrics = group.Metrics;\n\n if (groupMetrics !== undefined) {\n accumulator[keyName].reports[period] = parseFloat(groupMetrics.UnblendedCost.Amount ?? '0.0');\n }\n });\n }\n\n return accumulator;\n },\n {},\n );\n\n // cache the results for 2 hours\n await setReportsToCache(\n this.cache,\n Object.values(transformedData),\n this.providerName,\n accountName,\n query,\n 60 * 60 * 2 * 1000,\n );\n\n Object.values(transformedData).map((value: any) => {\n results.push(value);\n });\n } catch (e) {\n this.logger.error(e);\n errors.push({\n provider: this.providerName,\n name: `${this.providerName}/${accountName}`,\n error: e.message,\n });\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n return {\n reports: results,\n errors: errors,\n };\n }\n}\n","import { CostManagementClient, QueryDefinition } from '@azure/arm-costmanagement';\nimport { createHttpHeaders, createPipelineRequest } from '@azure/core-rest-pipeline';\nimport { ClientSecretCredential } from '@azure/identity';\nimport { CacheService, DatabaseService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport { getCategoryByServiceName, getCategoryMappings, getReportsFromCache, setReportsToCache } from './functions';\nimport { ClientResponse, CloudProviderError, CostQuery, Report } from './types';\n\nexport class AzureClient implements InfraWalletApi {\n static create(config: Config, database: DatabaseService, cache: CacheService, logger: LoggerService) {\n return new AzureClient('Azure', config, database, cache, logger);\n }\n\n constructor(\n private readonly providerName: string,\n private readonly config: Config,\n private readonly database: DatabaseService,\n private readonly cache: CacheService,\n private readonly logger: LoggerService,\n ) {}\n\n convertServiceName(serviceName: string): string {\n let convertedName = serviceName;\n\n const prefixes = ['Azure'];\n\n for (const prefix of prefixes) {\n if (serviceName.startsWith(prefix)) {\n convertedName = serviceName.slice(prefix.length).trim();\n }\n }\n\n return `${this.providerName}/${convertedName}`;\n }\n\n formatDate(dateNumber: number): string | null {\n // dateNumber example: 20240407\n const dateString = dateNumber.toString();\n\n if (dateString.length !== 8) {\n return null;\n }\n\n const year = dateString.slice(0, 4);\n const month = dateString.slice(4, 6);\n const day = dateString.slice(6);\n\n return `${year}-${month}-${day}`;\n }\n\n async fetchDataWithRetry(client: CostManagementClient, url: string, body: any, maxRetries = 5): Promise<any> {\n let retries = 0;\n\n while (retries < maxRetries) {\n const request = createPipelineRequest({\n url: url,\n method: 'POST',\n body: JSON.stringify(body),\n headers: createHttpHeaders({\n 'Content-Type': 'application/json',\n }),\n });\n const response = await client.pipeline.sendRequest(client, request);\n if (response.status === 200) {\n return JSON.parse(response.bodyAsText || '{}');\n } else if (response.status === 429) {\n const retryAfter = parseInt(\n response.headers.get('x-ms-ratelimit-microsoft.costmanagement-entity-retry-after') || '60',\n 10,\n );\n this.logger.warn(`Hit Azure rate limit, retrying after ${retryAfter} seconds...`);\n await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));\n retries++;\n } else {\n throw new Error(response.bodyAsText as string);\n }\n }\n\n throw new Error('Max retries exceeded');\n }\n\n async queryAzureCostExplorer(\n azureClient: CostManagementClient,\n subscription: string,\n granularity: string,\n groups: { type: string; name: string }[],\n startDate: moment.Moment,\n endDate: moment.Moment,\n ) {\n // Azure SDK doesn't support pagination, so sending HTTP request directly\n const url = `https://management.azure.com/subscriptions/${subscription}/providers/Microsoft.CostManagement/query?api-version=2022-10-01`;\n\n const query: QueryDefinition = {\n type: 'ActualCost',\n dataset: {\n granularity: granularity,\n aggregation: { totalCostUSD: { name: 'CostUSD', function: 'Sum' } },\n grouping: groups,\n },\n timeframe: 'Custom',\n timePeriod: {\n from: startDate.toDate(),\n to: endDate.toDate(),\n },\n };\n\n let result = await this.fetchDataWithRetry(azureClient, url, query);\n let allResults = result.properties.rows;\n\n while (result.properties.nextLink) {\n result = await this.fetchDataWithRetry(azureClient, result.properties.nextLink, query);\n allResults = allResults.concat(result.properties.rows);\n }\n\n return allResults;\n }\n\n async fetchCostsFromCloud(query: CostQuery): Promise<ClientResponse> {\n const conf = this.config.getOptionalConfigArray('backend.infraWallet.integrations.azure');\n if (!conf) {\n return { reports: [], errors: [] };\n }\n\n const categoryMappings = await getCategoryMappings(this.database, this.providerName);\n\n const promises = [];\n const results: Report[] = [];\n const errors: CloudProviderError[] = [];\n\n const groupPairs = [{ type: 'Dimension', name: 'ServiceName' }];\n for (const c of conf) {\n const accountName = c.getString('name');\n\n // first check if there is any cached\n const cachedCosts = await getReportsFromCache(this.cache, this.providerName, accountName, query);\n if (cachedCosts) {\n this.logger.debug(`${this.providerName}/${accountName} costs from cache`);\n cachedCosts.map(cost => {\n results.push(cost);\n });\n continue;\n }\n\n const subscriptionId = c.getString('subscriptionId');\n const tenantId = c.getString('tenantId');\n const clientId = c.getString('clientId');\n const clientSecret = c.getString('clientSecret');\n const credential = new ClientSecretCredential(tenantId as string, clientId as string, clientSecret as string);\n const client = new CostManagementClient(credential);\n const tags = c.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 const promise = (async () => {\n try {\n const costResponse = await this.queryAzureCostExplorer(\n client,\n subscriptionId as string,\n query.granularity,\n groupPairs,\n moment(parseInt(query.startTime, 10)),\n moment(parseInt(query.endTime, 10)),\n );\n\n /* \n Monthly cost sample:\n [\n 123.456,\n \"2024-04-07T00:00:00\", // BillingMonth\n \"Azure App Service\",\n \"EUR\"\n ]\n \n Daily cost sample:\n [\n 12.3456,\n 20240407, // UsageDate\n \"Azure App Service\",\n \"EUR\"\n ]\n */\n const transformedData = reduce(\n costResponse,\n (accumulator: { [key: string]: Report }, row) => {\n const cost = row[0];\n let date = row[1];\n const serviceName = row[2];\n\n if (query.granularity.toUpperCase() === 'DAILY') {\n // 20240407 -> \"2024-04-07\"\n date = this.formatDate(date);\n }\n\n let keyName = accountName;\n for (let i = 0; i < groupPairs.length; i++) {\n keyName += `->${row[i + 2]}`;\n }\n\n if (!accumulator[keyName]) {\n accumulator[keyName] = {\n id: keyName,\n name: `${this.providerName}/${accountName}`,\n service: this.convertServiceName(serviceName),\n category: getCategoryByServiceName(serviceName, categoryMappings),\n provider: this.providerName,\n reports: {},\n ...tagKeyValues,\n };\n }\n\n if (!moment(date).isBefore(moment(parseInt(query.startTime, 10)))) {\n if (query.granularity.toUpperCase() === 'MONTHLY') {\n const yearMonth = date.substring(0, 7);\n accumulator[keyName].reports[yearMonth] = parseFloat(cost);\n } else {\n accumulator[keyName].reports[date] = parseFloat(cost);\n }\n }\n return accumulator;\n },\n {},\n );\n\n // cache the results for 2 hours\n await setReportsToCache(\n this.cache,\n Object.values(transformedData),\n this.providerName,\n accountName,\n query,\n 60 * 60 * 2 * 1000,\n );\n\n Object.values(transformedData).map((value: Report) => {\n results.push(value);\n });\n } catch (e) {\n this.logger.error(e);\n errors.push({\n provider: this.providerName,\n name: `${this.providerName}/${accountName}`,\n error: e.message,\n });\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n return {\n reports: results,\n errors: errors,\n };\n }\n}\n","import { CacheService, DatabaseService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { BigQuery } from '@google-cloud/bigquery';\nimport { reduce } from 'lodash';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport { getCategoryByServiceName, getCategoryMappings, getReportsFromCache, setReportsToCache } from './functions';\nimport { ClientResponse, CloudProviderError, CostQuery, Report } from './types';\n\nexport class GCPClient implements InfraWalletApi {\n static create(config: Config, database: DatabaseService, cache: CacheService, logger: LoggerService) {\n return new GCPClient('GCP', config, database, cache, logger);\n }\n\n constructor(\n private readonly providerName: string,\n private readonly config: Config,\n private readonly database: DatabaseService,\n private readonly cache: CacheService,\n private readonly logger: LoggerService,\n ) {}\n\n convertServiceName(serviceName: string): string {\n let convertedName = serviceName;\n\n const prefixes = ['Google Cloud'];\n\n for (const prefix of prefixes) {\n if (serviceName.startsWith(prefix)) {\n convertedName = serviceName.slice(prefix.length).trim();\n }\n }\n\n return `${this.providerName}/${convertedName}`;\n }\n\n async queryBigQuery(keyFilePath: string, projectId: string, datasetId: string, tableId: string, query: CostQuery) {\n // Configure a JWT auth client\n const options = {\n keyFilename: keyFilePath,\n projectId: projectId,\n };\n\n // Initialize the BigQuery API\n const bigquery = new BigQuery(options);\n try {\n const periodFormat = query.granularity.toUpperCase() === 'MONTHLY' ? '%Y-%m' : '%Y-%m-%d';\n const sql = `\n SELECT\n project.name AS project,\n service.description AS service,\n FORMAT_TIMESTAMP('${periodFormat}', usage_start_time) AS period,\n SUM(cost) AS total_cost\n FROM\n \\`${projectId}.${datasetId}.${tableId}\\`\n WHERE\n project.name IS NOT NULL\n AND cost > 0\n AND usage_start_time >= TIMESTAMP_MILLIS(${query.startTime})\n AND usage_start_time <= TIMESTAMP_MILLIS(${query.endTime})\n GROUP BY\n project, service, period\n ORDER BY\n project, period, total_cost DESC`;\n\n // Run the query as a job\n const [job] = await bigquery.createQueryJob({\n query: sql,\n location: 'US',\n });\n\n // Wait for the query to finish\n const [rows] = await job.getQueryResults();\n\n return rows;\n } catch (err) {\n throw new Error(err.message);\n }\n }\n\n async fetchCostsFromCloud(query: CostQuery): Promise<ClientResponse> {\n const conf = this.config.getOptionalConfigArray('backend.infraWallet.integrations.gcp');\n if (!conf) {\n return { reports: [], errors: [] };\n }\n\n const promises = [];\n const results: Report[] = [];\n const errors: CloudProviderError[] = [];\n\n for (const c of conf) {\n const accountName = c.getString('name');\n\n // first check if there is any cached\n const cachedCosts = await getReportsFromCache(this.cache, this.providerName, accountName, query);\n if (cachedCosts) {\n this.logger.debug(`${this.providerName}/${accountName} costs from cache`);\n cachedCosts.map(cost => {\n results.push(cost);\n });\n continue;\n }\n\n const keyFilePath = c.getString('keyFilePath');\n const projectId = c.getString('projectId');\n const datasetId = c.getString('datasetId');\n const tableId = c.getString('tableId');\n const tags = c.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 const categoryMappings = await getCategoryMappings(this.database, this.providerName);\n\n const promise = (async () => {\n try {\n const costResponse = await this.queryBigQuery(keyFilePath, projectId, datasetId, tableId, query);\n const transformedData = reduce(\n costResponse,\n (acc: { [key: string]: Report }, row) => {\n const period = row.period;\n const keyName = `${accountName}_${row.project}_${row.service}`;\n\n if (!acc[keyName]) {\n acc[keyName] = {\n id: keyName,\n name: `${this.providerName}/${accountName}`,\n service: this.convertServiceName(row.service),\n category: getCategoryByServiceName(row.service, categoryMappings),\n provider: this.providerName,\n reports: {},\n ...{ project: row.project }, // TODO: how should we handle the project field? for now, we add project name as a field in the report\n ...tagKeyValues, // note that if there is a tag `project:foo` in config, it overrides the project field set above\n };\n }\n\n acc[keyName].reports[period] = row.total_cost;\n\n return acc;\n },\n {},\n );\n\n // cache the results for 2 hours\n await setReportsToCache(\n this.cache,\n Object.values(transformedData),\n this.providerName,\n accountName,\n query,\n 60 * 60 * 2 * 1000,\n );\n\n Object.values(transformedData).map((value: any) => {\n results.push(value);\n });\n } catch (e) {\n this.logger.error(e);\n errors.push({\n provider: this.providerName,\n name: `${this.providerName}/${accountName}`,\n error: e.message,\n });\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n return {\n reports: results,\n errors: errors,\n };\n }\n}\n","import { errorHandler } from '@backstage/backend-common';\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 { AwsClient } from './AwsClient';\nimport { AzureClient } from './AzureClient';\nimport { GCPClient } from './GCPClient';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport { CloudProviderError, Report } from './types';\n\nexport interface RouterOptions {\n logger: LoggerService;\n config: Config;\n cache: CacheService;\n database: DatabaseService;\n}\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\nexport async function createRouter(options: RouterOptions): Promise<express.Router> {\n const { logger, config, cache, database } = options;\n // do database migrations here to support the legacy backend system\n await setUpDatabase(database);\n\n const router = Router();\n router.use(express.json());\n\n const azureClient = AzureClient.create(config, database, cache, logger);\n const awsClient = AwsClient.create(config, database, cache, logger);\n const gcpClient = GCPClient.create(config, database, cache, logger);\n const cloudClients: InfraWalletApi[] = [azureClient, awsClient, gcpClient];\n\n router.get('/health', (_, response) => {\n logger.info('PONG!');\n response.json({ status: 'ok' });\n });\n\n router.get('/reports', async (request, response) => {\n const filters = request.query.filters as string;\n const groups = request.query.groups as string;\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: Report[] = [];\n const errors: CloudProviderError[] = [];\n\n cloudClients.forEach(async client => {\n const fetchCloudCosts = (async () => {\n try {\n const clientResponse = await client.fetchCostsFromCloud({\n filters: filters,\n groups: groups,\n granularity: granularity,\n startTime: startTime,\n endTime: endTime,\n });\n clientResponse.errors.forEach(e => {\n errors.push(e);\n });\n clientResponse.reports.forEach(cost => {\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 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.use(errorHandler());\n return router;\n}\n","import { coreServices, createBackendPlugin } from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * infraWalletPlugin backend plugin\n *\n * @public\n */\nexport const infraWalletPlugin = createBackendPlugin({\n pluginId: 'infrawallet',\n register(env) {\n env.registerInit({\n deps: {\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n cache: coreServices.cache,\n database: coreServices.database,\n },\n async init({ httpRouter, logger, config, cache, database }) {\n httpRouter.use(\n await createRouter({\n logger,\n config,\n cache,\n database,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n },\n });\n },\n});\n"],"names":["STSClient","AssumeRoleCommand","CostExplorerClient","moment","GetCostAndUsageCommand","reduce","_a","createPipelineRequest","createHttpHeaders","ClientSecretCredential","CostManagementClient","bigquery","BigQuery","resolvePackagePath","Router","express","errorHandler","createBackendPlugin","coreServices"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAGsB,eAAA,mBAAA,CACpB,UACA,QACwC,EAAA;AACxC,EAAA,MAAM,SAAwC,EAAC,CAAA;AAC/C,EAAM,MAAA,MAAA,GAAS,MAAM,QAAA,CAAS,SAAU,EAAA,CAAA;AACxC,EAAA,MAAM,gBAAmB,GAAA,MAAM,MAC5B,CAAA,KAAA,CAAM,EAAE,QAAU,EAAA,QAAA,CAAS,WAAY,EAAA,EAAG,CAAA,CAC1C,MAAO,EAAA,CACP,KAAsB,2BAA2B,CAAA,CAAA;AACpD,EAAA,gBAAA,CAAiB,QAAQ,CAAW,OAAA,KAAA;AAClC,IAAI,IAAA,OAAO,OAAQ,CAAA,mBAAA,KAAwB,QAAU,EAAA;AAEnD,MAAA,IAAA,CAAK,MAAM,OAAQ,CAAA,mBAAmB,CAAE,CAAA,OAAA,CAAQ,CAAC,OAAoB,KAAA;AACnE,QAAO,MAAA,CAAA,OAAO,IAAI,OAAQ,CAAA,QAAA,CAAA;AAAA,OAC3B,CAAA,CAAA;AAAA,KACI,MAAA;AACL,MAAQ,OAAA,CAAA,mBAAA,CAAoB,OAAQ,CAAA,CAAC,OAAoB,KAAA;AACvD,QAAO,MAAA,CAAA,OAAO,IAAI,OAAQ,CAAA,QAAA,CAAA;AAAA,OAC3B,CAAA,CAAA;AAAA,KACH;AAAA,GACD,CAAA,CAAA;AAGD,EAAM,MAAA,iBAAA,GAAoB,MAAM,MAAA,CAC7B,KAAM,CAAA,EAAE,QAAmB,EAAC,CAC5B,CAAA,MAAA,EACA,CAAA,IAAA,CAAsB,4BAA4B,CAAA,CAAA;AACrD,EAAA,iBAAA,CAAkB,QAAQ,CAAW,OAAA,KAAA;AACnC,IAAI,IAAA,OAAO,OAAQ,CAAA,mBAAA,KAAwB,QAAU,EAAA;AAEnD,MAAA,IAAA,CAAK,MAAM,OAAQ,CAAA,mBAAmB,CAAE,CAAA,OAAA,CAAQ,CAAC,OAAoB,KAAA;AACnE,QAAO,MAAA,CAAA,OAAO,IAAI,OAAQ,CAAA,QAAA,CAAA;AAAA,OAC3B,CAAA,CAAA;AAAA,KACI,MAAA;AACL,MAAQ,OAAA,CAAA,mBAAA,CAAoB,OAAQ,CAAA,CAAC,OAAoB,KAAA;AACvD,QAAO,MAAA,CAAA,OAAO,IAAI,OAAQ,CAAA,QAAA,CAAA;AAAA,OAC3B,CAAA,CAAA;AAAA,KACH;AAAA,GACD,CAAA,CAAA;AAED,EAAO,OAAA,MAAA,CAAA;AACT,CAAA;AAEgB,SAAA,wBAAA,CAAyB,aAAqB,gBAAyD,EAAA;AACrH,EAAA,IAAI,eAAe,gBAAkB,EAAA;AACnC,IAAA,OAAO,iBAAiB,WAAW,CAAA,CAAA;AAAA,GACrC;AAEA,EAAO,OAAA,eAAA,CAAA;AACT,CAAA;AAEA,eAAsB,mBACpB,CAAA,KAAA,EACA,QACA,EAAA,SAAA,EACA,KAC+B,EAAA;AAC/B,EAAA,MAAM,QAAW,GAAA;AAAA,IACf,QAAA;AAAA,IACA,SAAA;AAAA,IACA,KAAM,CAAA,OAAA;AAAA,IACN,KAAM,CAAA,MAAA;AAAA,IACN,KAAM,CAAA,WAAA;AAAA,IACN,KAAM,CAAA,SAAA;AAAA,IACN,KAAM,CAAA,OAAA;AAAA,GACR,CAAE,KAAK,GAAG,CAAA,CAAA;AACV,EAAA,MAAM,WAAe,GAAA,MAAM,KAAM,CAAA,GAAA,CAAI,QAAQ,CAAA,CAAA;AAC7C,EAAO,OAAA,WAAA,CAAA;AACT,CAAA;AAEA,eAAsB,kBACpB,KACA,EAAA,OAAA,EACA,QACA,EAAA,SAAA,EACA,OACA,GACA,EAAA;AACA,EAAA,MAAM,QAAW,GAAA;AAAA,IACf,QAAA;AAAA,IACA,SAAA;AAAA,IACA,KAAM,CAAA,OAAA;AAAA,IACN,KAAM,CAAA,MAAA;AAAA,IACN,KAAM,CAAA,WAAA;AAAA,IACN,KAAM,CAAA,SAAA;AAAA,IACN,KAAM,CAAA,OAAA;AAAA,GACR,CAAE,KAAK,GAAG,CAAA,CAAA;AACV,EAAM,MAAA,KAAA,CAAM,GAAI,CAAA,QAAA,EAAU,OAAS,EAAA;AAAA,IACjC,GAAK,EAAA,GAAA,CAAqB;AAAA,GAC3B,CAAA,CAAA;AACH;;AC/EO,MAAM,SAAoC,CAAA;AAAA,EAK/C,WACmB,CAAA,YAAA,EACA,MACA,EAAA,QAAA,EACA,OACA,MACjB,EAAA;AALiB,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA,CAAA;AACA,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AAAA,GAChB;AAAA,EAVH,OAAO,MAAA,CAAO,MAAgB,EAAA,QAAA,EAA2B,OAAqB,MAAuB,EAAA;AACnG,IAAA,OAAO,IAAI,SAAU,CAAA,KAAA,EAAO,MAAQ,EAAA,QAAA,EAAU,OAAO,MAAM,CAAA,CAAA;AAAA,GAC7D;AAAA,EAUA,mBAAmB,WAA6B,EAAA;AAC9C,IAAA,IAAI,aAAgB,GAAA,WAAA,CAAA;AAEpB,IAAM,MAAA,QAAA,GAAW,CAAC,QAAA,EAAU,KAAK,CAAA,CAAA;AAEjC,IAAM,MAAA,OAAA,uBAAc,GAAoB,CAAA;AAAA,MACtC,CAAC,mCAAmC,iBAAiB,CAAA;AAAA,MACrD,CAAC,yBAAyB,6BAA6B,CAAA;AAAA,MACvD,CAAC,+BAA+B,mCAAmC,CAAA;AAAA,MACnE,CAAC,0BAA0B,6BAA6B,CAAA;AAAA,MACxD,CAAC,sCAAsC,0CAA0C,CAAA;AAAA,MACjF,CAAC,4CAA4C,gDAAgD,CAAA;AAAA,MAC7F,CAAC,6BAA6B,iCAAiC,CAAA;AAAA,MAC/D,CAAC,gCAAgC,kCAAkC,CAAA;AAAA,MACnE,CAAC,wBAAwB,4BAA4B,CAAA;AAAA,MACrD,CAAC,+BAA+B,mCAAmC,CAAA;AAAA,MACnE,CAAC,8BAA8B,kCAAkC,CAAA;AAAA,KAClE,CAAA,CAAA;AAED,IAAA,KAAA,MAAW,UAAU,QAAU,EAAA;AAC7B,MAAI,IAAA,WAAA,CAAY,UAAW,CAAA,MAAM,CAAG,EAAA;AAClC,QAAA,aAAA,GAAgB,WAAY,CAAA,KAAA,CAAM,MAAO,CAAA,MAAM,EAAE,IAAK,EAAA,CAAA;AAAA,OACxD;AAAA,KACF;AAEA,IAAI,IAAA,OAAA,CAAQ,GAAI,CAAA,aAAa,CAAG,EAAA;AAC9B,MAAgB,aAAA,GAAA,OAAA,CAAQ,GAAI,CAAA,aAAa,CAAK,IAAA,aAAA,CAAA;AAAA,KAChD;AAEA,IAAA,OAAO,CAAG,EAAA,IAAA,CAAK,YAAY,CAAA,CAAA,EAAI,aAAa,CAAA,CAAA,CAAA;AAAA,GAC9C;AAAA,EAEA,MAAM,oBAAoB,KAA2C,EAAA;AACnE,IAAA,MAAM,IAAO,GAAA,IAAA,CAAK,MAAO,CAAA,sBAAA,CAAuB,sCAAsC,CAAA,CAAA;AACtF,IAAA,IAAI,CAAC,IAAM,EAAA;AACT,MAAA,OAAO,EAAE,OAAS,EAAA,EAAI,EAAA,MAAA,EAAQ,EAAG,EAAA,CAAA;AAAA,KACnC;AAEA,IAAA,MAAM,WAAW,EAAC,CAAA;AAClB,IAAA,MAAM,UAAoB,EAAC,CAAA;AAC3B,IAAA,MAAM,SAA+B,EAAC,CAAA;AAEtC,IAAA,KAAA,CAAM,MAAO,CAAA,KAAA,CAAM,GAAG,CAAA,CAAE,QAAQ,CAAS,KAAA,KAAA;AACvC,MAAI,IAAA,KAAA,CAAM,QAAS,CAAA,GAAG,CAAG,EAAA;AACvB,QAAqB,KAAA,CAAM,MAAM,GAAG,EAAA;AACN,OAChC;AAAA,KACD,CAAA,CAAA;AAED,IAAA,KAAA,MAAW,KAAK,IAAM,EAAA;AACpB,MAAM,MAAA,WAAA,GAAc,CAAE,CAAA,SAAA,CAAU,MAAM,CAAA,CAAA;AAGtC,MAAM,MAAA,WAAA,GAAc,MAAM,mBAAoB,CAAA,IAAA,CAAK,OAAO,IAAK,CAAA,YAAA,EAAc,aAAa,KAAK,CAAA,CAAA;AAC/F,MAAA,IAAI,WAAa,EAAA;AACf,QAAA,IAAA,CAAK,OAAO,KAAM,CAAA,CAAA,EAAG,KAAK,YAAY,CAAA,CAAA,EAAI,WAAW,CAAmB,iBAAA,CAAA,CAAA,CAAA;AACxE,QAAA,WAAA,CAAY,IAAI,CAAQ,IAAA,KAAA;AACtB,UAAA,OAAA,CAAQ,KAAK,IAAI,CAAA,CAAA;AAAA,SAClB,CAAA,CAAA;AACD,QAAA,SAAA;AAAA,OACF;AAEA,MAAM,MAAA,SAAA,GAAY,CAAE,CAAA,SAAA,CAAU,WAAW,CAAA,CAAA;AACzC,MAAM,MAAA,eAAA,GAAkB,CAAE,CAAA,SAAA,CAAU,iBAAiB,CAAA,CAAA;AACrD,MAAM,MAAA,WAAA,GAAc,CAAE,CAAA,iBAAA,CAAkB,aAAa,CAAA,CAAA;AACrD,MAAM,MAAA,eAAA,GAAkB,CAAE,CAAA,iBAAA,CAAkB,iBAAiB,CAAA,CAAA;AAC7D,MAAM,MAAA,IAAA,GAAO,CAAE,CAAA,sBAAA,CAAuB,MAAM,CAAA,CAAA;AAC5C,MAAA,MAAM,eAA0C,EAAC,CAAA;AACjD,MAAA,IAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,IAAA,CAAM,QAAQ,CAAO,GAAA,KAAA;AACnB,QAAA,MAAM,CAAC,CAAG,EAAA,CAAC,CAAI,GAAA,GAAA,CAAI,MAAM,GAAG,CAAA,CAAA;AAC5B,QAAA,YAAA,CAAa,CAAE,CAAA,IAAA,EAAM,CAAA,GAAI,EAAE,IAAK,EAAA,CAAA;AAAA,OAClC,CAAA,CAAA;AACA,MAAA,MAAM,mBAAmB,MAAM,mBAAA,CAAoB,IAAK,CAAA,QAAA,EAAU,KAAK,YAAY,CAAA,CAAA;AAEnF,MAAA,IAAI,YAAY,EAAC,CAAA;AACjB,MAAA,IAAI,eAAe,eAAiB,EAAA;AAClC,QAAY,SAAA,GAAA;AAAA,UACV,MAAQ,EAAA,WAAA;AAAA,UACR,WAAa,EAAA;AAAA,YACX,WAAA;AAAA,YACA,eAAiB,EAAA,eAAA;AAAA,WACnB;AAAA,SACF,CAAA;AAAA,OACK,MAAA;AACL,QAAY,SAAA,GAAA;AAAA,UACV,MAAQ,EAAA,WAAA;AAAA,SACV,CAAA;AAAA,OACF;AACA,MAAA,MAAM,WAAW,YAAY;AApHnC,QAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA;AAqHQ,QAAI,IAAA;AACF,UAAM,MAAA,MAAA,GAAS,IAAIA,mBAAA,CAAU,SAAS,CAAA,CAAA;AACtC,UAAA,MAAM,YAAe,GAAA;AAAA;AAAA,YAEnB,OAAS,EAAA,CAAA,aAAA,EAAgB,SAAS,CAAA,MAAA,EAAS,eAAe,CAAA,CAAA;AAAA,YAC1D,eAAiB,EAAA,oBAAA;AAAA,WACnB,CAAA;AACA,UAAM,MAAA,iBAAA,GAAoB,IAAIC,2BAAA,CAAkB,YAAY,CAAA,CAAA;AAC5D,UAAA,MAAM,kBAAqB,GAAA,MAAM,MAAO,CAAA,IAAA,CAAK,iBAAiB,CAAA,CAAA;AAE9D,UAAM,MAAA,WAAA,GAAc,IAAIC,qCAAmB,CAAA;AAAA,YACzC,MAAQ,EAAA,WAAA;AAAA,YACR,WAAa,EAAA;AAAA,cACX,WAAA,EAAA,CAAa,EAAmB,GAAA,kBAAA,CAAA,WAAA,KAAnB,IAAgC,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,WAAA;AAAA,cAC7C,eAAA,EAAA,CAAiB,EAAmB,GAAA,kBAAA,CAAA,WAAA,KAAnB,IAAgC,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,eAAA;AAAA,cACjD,YAAA,EAAA,CAAc,EAAmB,GAAA,kBAAA,CAAA,WAAA,KAAnB,IAAgC,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,YAAA;AAAA,aAChD;AAAA,WACD,CAAA,CAAA;AAGD,UAAA,IAAI,sBAA6B,EAAC,CAAA;AAClC,UAAA,IAAI,aAAgB,GAAA,KAAA,CAAA,CAAA;AAEpB,UAAG,GAAA;AACD,YAAA,MAAM,KAAqC,GAAA;AAAA,cACzC,UAAY,EAAA;AAAA,gBACV,KAAA,EAAOC,wBAAO,QAAS,CAAA,KAAA,CAAM,WAAW,EAAE,CAAC,CAAE,CAAA,MAAA,CAAO,YAAY,CAAA;AAAA,gBAChE,GAAA,EAAKA,wBAAO,QAAS,CAAA,KAAA,CAAM,SAAS,EAAE,CAAC,CAAE,CAAA,MAAA,CAAO,YAAY,CAAA;AAAA,eAC9D;AAAA,cACA,WAAA,EAAa,KAAM,CAAA,WAAA,CAAY,WAAY,EAAA;AAAA,cAC3C,MAAA,EAAQ,EAAE,UAAA,EAAY,EAAE,GAAA,EAAK,eAAe,MAAQ,EAAA,CAAC,OAAO,CAAA,EAAI,EAAA;AAAA,cAChE,SAAS,CAAC,EAAE,MAAM,WAAa,EAAA,GAAA,EAAK,WAAW,CAAA;AAAA,cAC/C,OAAA,EAAS,CAAC,eAAe,CAAA;AAAA,cACzB,aAAe,EAAA,aAAA;AAAA,aACjB,CAAA;AAEA,YAAM,MAAA,cAAA,GAAiB,IAAIC,yCAAA,CAAuB,KAAK,CAAA,CAAA;AACvD,YAAA,MAAM,oBAAuB,GAAA,MAAM,WAAY,CAAA,IAAA,CAAK,cAAc,CAAA,CAAA;AAElE,YAAsB,mBAAA,GAAA,mBAAA,CAAoB,MAAO,CAAA,oBAAA,CAAqB,aAAa,CAAA,CAAA;AACnF,YAAA,aAAA,GAAgB,oBAAqB,CAAA,aAAA,CAAA;AAAA,WAC9B,QAAA,aAAA,EAAA;AAET,UAAA,MAAM,eAAkB,GAAAC,aAAA;AAAA,YACtB,mBAAA;AAAA,YACA,CAAC,aAAwC,GAAQ,KAAA;AAlK7D,cAAAC,IAAAA,GAAAA,CAAAA;AAmKc,cAAA,MAAM,OAAUA,GAAAA,CAAAA,GAAAA,GAAA,GAAI,CAAA,UAAA,KAAJ,gBAAAA,GAAgB,CAAA,KAAA,CAAA;AAChC,cAAA,IAAI,MAAS,GAAA,SAAA,CAAA;AACb,cAAA,IAAI,OAAS,EAAA;AACX,gBAAA,IAAI,KAAM,CAAA,WAAA,CAAY,WAAY,EAAA,KAAM,SAAW,EAAA;AACjD,kBAAS,MAAA,GAAA,OAAA,CAAQ,SAAU,CAAA,CAAA,EAAG,CAAC,CAAA,CAAA;AAAA,iBAC1B,MAAA;AACL,kBAAS,MAAA,GAAA,OAAA,CAAA;AAAA,iBACX;AAAA,eACF;AACA,cAAA,IAAI,IAAI,MAAQ,EAAA;AACd,gBAAI,GAAA,CAAA,MAAA,CAAO,OAAQ,CAAA,CAAC,KAAe,KAAA;AA7KnD,kBAAAA,IAAAA,GAAAA,CAAAA;AA8KkB,kBAAA,MAAM,cAAc,KAAM,CAAA,IAAA,GAAO,KAAM,CAAA,IAAA,CAAK,CAAC,CAAI,GAAA,EAAA,CAAA;AACjD,kBAAA,MAAM,OAAU,GAAA,CAAA,EAAG,WAAW,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA,CAAA;AAE7C,kBAAI,IAAA,CAAC,WAAY,CAAA,OAAO,CAAG,EAAA;AACzB,oBAAA,WAAA,CAAY,OAAO,CAAI,GAAA;AAAA,sBACrB,EAAI,EAAA,OAAA;AAAA,sBACJ,IAAM,EAAA,CAAA,EAAG,IAAK,CAAA,YAAY,IAAI,WAAW,CAAA,CAAA;AAAA,sBACzC,OAAA,EAAS,IAAK,CAAA,kBAAA,CAAmB,WAAW,CAAA;AAAA,sBAC5C,QAAA,EAAU,wBAAyB,CAAA,WAAA,EAAa,gBAAgB,CAAA;AAAA,sBAChE,UAAU,IAAK,CAAA,YAAA;AAAA,sBACf,SAAS,EAAC;AAAA,sBACV,GAAG,YAAA;AAAA,qBACL,CAAA;AAAA,mBACF;AAEA,kBAAA,MAAM,eAAe,KAAM,CAAA,OAAA,CAAA;AAE3B,kBAAA,IAAI,iBAAiB,KAAW,CAAA,EAAA;AAC9B,oBAAA,WAAA,CAAY,OAAO,CAAA,CAAE,OAAQ,CAAA,MAAM,CAAI,GAAA,UAAA,CAAA,CAAWA,GAAA,GAAA,YAAA,CAAa,aAAc,CAAA,MAAA,KAA3B,IAAAA,GAAAA,GAAAA,GAAqC,KAAK,CAAA,CAAA;AAAA,mBAC9F;AAAA,iBACD,CAAA,CAAA;AAAA,eACH;AAEA,cAAO,OAAA,WAAA,CAAA;AAAA,aACT;AAAA,YACA,EAAC;AAAA,WACH,CAAA;AAGA,UAAM,MAAA,iBAAA;AAAA,YACJ,IAAK,CAAA,KAAA;AAAA,YACL,MAAA,CAAO,OAAO,eAAe,CAAA;AAAA,YAC7B,IAAK,CAAA,YAAA;AAAA,YACL,WAAA;AAAA,YACA,KAAA;AAAA,YACA,EAAA,GAAK,KAAK,CAAI,GAAA,GAAA;AAAA,WAChB,CAAA;AAEA,UAAA,MAAA,CAAO,MAAO,CAAA,eAAe,CAAE,CAAA,GAAA,CAAI,CAAC,KAAe,KAAA;AACjD,YAAA,OAAA,CAAQ,KAAK,KAAK,CAAA,CAAA;AAAA,WACnB,CAAA,CAAA;AAAA,iBACM,CAAG,EAAA;AACV,UAAK,IAAA,CAAA,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA;AACnB,UAAA,MAAA,CAAO,IAAK,CAAA;AAAA,YACV,UAAU,IAAK,CAAA,YAAA;AAAA,YACf,IAAM,EAAA,CAAA,EAAG,IAAK,CAAA,YAAY,IAAI,WAAW,CAAA,CAAA;AAAA,YACzC,OAAO,CAAE,CAAA,OAAA;AAAA,WACV,CAAA,CAAA;AAAA,SACH;AAAA,OACC,GAAA,CAAA;AACH,MAAA,QAAA,CAAS,KAAK,OAAO,CAAA,CAAA;AAAA,KACvB;AACA,IAAM,MAAA,OAAA,CAAQ,IAAI,QAAQ,CAAA,CAAA;AAC1B,IAAO,OAAA;AAAA,MACL,OAAS,EAAA,OAAA;AAAA,MACT,MAAA;AAAA,KACF,CAAA;AAAA,GACF;AACF;;AC7NO,MAAM,WAAsC,CAAA;AAAA,EAKjD,WACmB,CAAA,YAAA,EACA,MACA,EAAA,QAAA,EACA,OACA,MACjB,EAAA;AALiB,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA,CAAA;AACA,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AAAA,GAChB;AAAA,EAVH,OAAO,MAAA,CAAO,MAAgB,EAAA,QAAA,EAA2B,OAAqB,MAAuB,EAAA;AACnG,IAAA,OAAO,IAAI,WAAY,CAAA,OAAA,EAAS,MAAQ,EAAA,QAAA,EAAU,OAAO,MAAM,CAAA,CAAA;AAAA,GACjE;AAAA,EAUA,mBAAmB,WAA6B,EAAA;AAC9C,IAAA,IAAI,aAAgB,GAAA,WAAA,CAAA;AAEpB,IAAM,MAAA,QAAA,GAAW,CAAC,OAAO,CAAA,CAAA;AAEzB,IAAA,KAAA,MAAW,UAAU,QAAU,EAAA;AAC7B,MAAI,IAAA,WAAA,CAAY,UAAW,CAAA,MAAM,CAAG,EAAA;AAClC,QAAA,aAAA,GAAgB,WAAY,CAAA,KAAA,CAAM,MAAO,CAAA,MAAM,EAAE,IAAK,EAAA,CAAA;AAAA,OACxD;AAAA,KACF;AAEA,IAAA,OAAO,CAAG,EAAA,IAAA,CAAK,YAAY,CAAA,CAAA,EAAI,aAAa,CAAA,CAAA,CAAA;AAAA,GAC9C;AAAA,EAEA,WAAW,UAAmC,EAAA;AAE5C,IAAM,MAAA,UAAA,GAAa,WAAW,QAAS,EAAA,CAAA;AAEvC,IAAI,IAAA,UAAA,CAAW,WAAW,CAAG,EAAA;AAC3B,MAAO,OAAA,IAAA,CAAA;AAAA,KACT;AAEA,IAAA,MAAM,IAAO,GAAA,UAAA,CAAW,KAAM,CAAA,CAAA,EAAG,CAAC,CAAA,CAAA;AAClC,IAAA,MAAM,KAAQ,GAAA,UAAA,CAAW,KAAM,CAAA,CAAA,EAAG,CAAC,CAAA,CAAA;AACnC,IAAM,MAAA,GAAA,GAAM,UAAW,CAAA,KAAA,CAAM,CAAC,CAAA,CAAA;AAE9B,IAAA,OAAO,CAAG,EAAA,IAAI,CAAI,CAAA,EAAA,KAAK,IAAI,GAAG,CAAA,CAAA,CAAA;AAAA,GAChC;AAAA,EAEA,MAAM,kBAAmB,CAAA,MAAA,EAA8B,GAAa,EAAA,IAAA,EAAW,aAAa,CAAiB,EAAA;AAC3G,IAAA,IAAI,OAAU,GAAA,CAAA,CAAA;AAEd,IAAA,OAAO,UAAU,UAAY,EAAA;AAC3B,MAAA,MAAM,UAAUC,sCAAsB,CAAA;AAAA,QACpC,GAAA;AAAA,QACA,MAAQ,EAAA,MAAA;AAAA,QACR,IAAA,EAAM,IAAK,CAAA,SAAA,CAAU,IAAI,CAAA;AAAA,QACzB,SAASC,kCAAkB,CAAA;AAAA,UACzB,cAAgB,EAAA,kBAAA;AAAA,SACjB,CAAA;AAAA,OACF,CAAA,CAAA;AACD,MAAA,MAAM,WAAW,MAAM,MAAA,CAAO,QAAS,CAAA,WAAA,CAAY,QAAQ,OAAO,CAAA,CAAA;AAClE,MAAI,IAAA,QAAA,CAAS,WAAW,GAAK,EAAA;AAC3B,QAAA,OAAO,IAAK,CAAA,KAAA,CAAM,QAAS,CAAA,UAAA,IAAc,IAAI,CAAA,CAAA;AAAA,OAC/C,MAAA,IAAW,QAAS,CAAA,MAAA,KAAW,GAAK,EAAA;AAClC,QAAA,MAAM,UAAa,GAAA,QAAA;AAAA,UACjB,QAAS,CAAA,OAAA,CAAQ,GAAI,CAAA,4DAA4D,CAAK,IAAA,IAAA;AAAA,UACtF,EAAA;AAAA,SACF,CAAA;AACA,QAAA,IAAA,CAAK,MAAO,CAAA,IAAA,CAAK,CAAwC,qCAAA,EAAA,UAAU,CAAa,WAAA,CAAA,CAAA,CAAA;AAChF,QAAA,MAAM,IAAI,OAAQ,CAAA,CAAA,OAAA,KAAW,WAAW,OAAS,EAAA,UAAA,GAAa,GAAI,CAAC,CAAA,CAAA;AACnE,QAAA,OAAA,EAAA,CAAA;AAAA,OACK,MAAA;AACL,QAAM,MAAA,IAAI,KAAM,CAAA,QAAA,CAAS,UAAoB,CAAA,CAAA;AAAA,OAC/C;AAAA,KACF;AAEA,IAAM,MAAA,IAAI,MAAM,sBAAsB,CAAA,CAAA;AAAA,GACxC;AAAA,EAEA,MAAM,sBACJ,CAAA,WAAA,EACA,cACA,WACA,EAAA,MAAA,EACA,WACA,OACA,EAAA;AAEA,IAAM,MAAA,GAAA,GAAM,8CAA8C,YAAY,CAAA,gEAAA,CAAA,CAAA;AAEtE,IAAA,MAAM,KAAyB,GAAA;AAAA,MAC7B,IAAM,EAAA,YAAA;AAAA,MACN,OAAS,EAAA;AAAA,QACP,WAAA;AAAA,QACA,WAAA,EAAa,EAAE,YAAc,EAAA,EAAE,MAAM,SAAW,EAAA,QAAA,EAAU,OAAQ,EAAA;AAAA,QAClE,QAAU,EAAA,MAAA;AAAA,OACZ;AAAA,MACA,SAAW,EAAA,QAAA;AAAA,MACX,UAAY,EAAA;AAAA,QACV,IAAA,EAAM,UAAU,MAAO,EAAA;AAAA,QACvB,EAAA,EAAI,QAAQ,MAAO,EAAA;AAAA,OACrB;AAAA,KACF,CAAA;AAEA,IAAA,IAAI,SAAS,MAAM,IAAA,CAAK,kBAAmB,CAAA,WAAA,EAAa,KAAK,KAAK,CAAA,CAAA;AAClE,IAAI,IAAA,UAAA,GAAa,OAAO,UAAW,CAAA,IAAA,CAAA;AAEnC,IAAO,OAAA,MAAA,CAAO,WAAW,QAAU,EAAA;AACjC,MAAA,MAAA,GAAS,MAAM,IAAK,CAAA,kBAAA,CAAmB,aAAa,MAAO,CAAA,UAAA,CAAW,UAAU,KAAK,CAAA,CAAA;AACrF,MAAA,UAAA,GAAa,UAAW,CAAA,MAAA,CAAO,MAAO,CAAA,UAAA,CAAW,IAAI,CAAA,CAAA;AAAA,KACvD;AAEA,IAAO,OAAA,UAAA,CAAA;AAAA,GACT;AAAA,EAEA,MAAM,oBAAoB,KAA2C,EAAA;AACnE,IAAA,MAAM,IAAO,GAAA,IAAA,CAAK,MAAO,CAAA,sBAAA,CAAuB,wCAAwC,CAAA,CAAA;AACxF,IAAA,IAAI,CAAC,IAAM,EAAA;AACT,MAAA,OAAO,EAAE,OAAS,EAAA,EAAI,EAAA,MAAA,EAAQ,EAAG,EAAA,CAAA;AAAA,KACnC;AAEA,IAAA,MAAM,mBAAmB,MAAM,mBAAA,CAAoB,IAAK,CAAA,QAAA,EAAU,KAAK,YAAY,CAAA,CAAA;AAEnF,IAAA,MAAM,WAAW,EAAC,CAAA;AAClB,IAAA,MAAM,UAAoB,EAAC,CAAA;AAC3B,IAAA,MAAM,SAA+B,EAAC,CAAA;AAEtC,IAAA,MAAM,aAAa,CAAC,EAAE,MAAM,WAAa,EAAA,IAAA,EAAM,eAAe,CAAA,CAAA;AAC9D,IAAA,KAAA,MAAW,KAAK,IAAM,EAAA;AACpB,MAAM,MAAA,WAAA,GAAc,CAAE,CAAA,SAAA,CAAU,MAAM,CAAA,CAAA;AAGtC,MAAM,MAAA,WAAA,GAAc,MAAM,mBAAoB,CAAA,IAAA,CAAK,OAAO,IAAK,CAAA,YAAA,EAAc,aAAa,KAAK,CAAA,CAAA;AAC/F,MAAA,IAAI,WAAa,EAAA;AACf,QAAA,IAAA,CAAK,OAAO,KAAM,CAAA,CAAA,EAAG,KAAK,YAAY,CAAA,CAAA,EAAI,WAAW,CAAmB,iBAAA,CAAA,CAAA,CAAA;AACxE,QAAA,WAAA,CAAY,IAAI,CAAQ,IAAA,KAAA;AACtB,UAAA,OAAA,CAAQ,KAAK,IAAI,CAAA,CAAA;AAAA,SAClB,CAAA,CAAA;AACD,QAAA,SAAA;AAAA,OACF;AAEA,MAAM,MAAA,cAAA,GAAiB,CAAE,CAAA,SAAA,CAAU,gBAAgB,CAAA,CAAA;AACnD,MAAM,MAAA,QAAA,GAAW,CAAE,CAAA,SAAA,CAAU,UAAU,CAAA,CAAA;AACvC,MAAM,MAAA,QAAA,GAAW,CAAE,CAAA,SAAA,CAAU,UAAU,CAAA,CAAA;AACvC,MAAM,MAAA,YAAA,GAAe,CAAE,CAAA,SAAA,CAAU,cAAc,CAAA,CAAA;AAC/C,MAAA,MAAM,UAAa,GAAA,IAAIC,+BAAuB,CAAA,QAAA,EAAoB,UAAoB,YAAsB,CAAA,CAAA;AAC5G,MAAM,MAAA,MAAA,GAAS,IAAIC,sCAAA,CAAqB,UAAU,CAAA,CAAA;AAClD,MAAM,MAAA,IAAA,GAAO,CAAE,CAAA,sBAAA,CAAuB,MAAM,CAAA,CAAA;AAC5C,MAAA,MAAM,eAA0C,EAAC,CAAA;AACjD,MAAA,IAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,IAAA,CAAM,QAAQ,CAAO,GAAA,KAAA;AACnB,QAAA,MAAM,CAAC,CAAG,EAAA,CAAC,CAAI,GAAA,GAAA,CAAI,MAAM,GAAG,CAAA,CAAA;AAC5B,QAAA,YAAA,CAAa,CAAE,CAAA,IAAA,EAAM,CAAA,GAAI,EAAE,IAAK,EAAA,CAAA;AAAA,OAClC,CAAA,CAAA;AAEA,MAAA,MAAM,WAAW,YAAY;AAC3B,QAAI,IAAA;AACF,UAAM,MAAA,YAAA,GAAe,MAAM,IAAK,CAAA,sBAAA;AAAA,YAC9B,MAAA;AAAA,YACA,cAAA;AAAA,YACA,KAAM,CAAA,WAAA;AAAA,YACN,UAAA;AAAA,YACAP,uBAAO,CAAA,QAAA,CAAS,KAAM,CAAA,SAAA,EAAW,EAAE,CAAC,CAAA;AAAA,YACpCA,uBAAO,CAAA,QAAA,CAAS,KAAM,CAAA,OAAA,EAAS,EAAE,CAAC,CAAA;AAAA,WACpC,CAAA;AAmBA,UAAA,MAAM,eAAkB,GAAAE,aAAA;AAAA,YACtB,YAAA;AAAA,YACA,CAAC,aAAwC,GAAQ,KAAA;AAC/C,cAAM,MAAA,IAAA,GAAO,IAAI,CAAC,CAAA,CAAA;AAClB,cAAI,IAAA,IAAA,GAAO,IAAI,CAAC,CAAA,CAAA;AAChB,cAAM,MAAA,WAAA,GAAc,IAAI,CAAC,CAAA,CAAA;AAEzB,cAAA,IAAI,KAAM,CAAA,WAAA,CAAY,WAAY,EAAA,KAAM,OAAS,EAAA;AAE/C,gBAAO,IAAA,GAAA,IAAA,CAAK,WAAW,IAAI,CAAA,CAAA;AAAA,eAC7B;AAEA,cAAA,IAAI,OAAU,GAAA,WAAA,CAAA;AACd,cAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,UAAA,CAAW,QAAQ,CAAK,EAAA,EAAA;AAC1C,gBAAA,OAAA,IAAW,CAAK,EAAA,EAAA,GAAA,CAAI,CAAI,GAAA,CAAC,CAAC,CAAA,CAAA,CAAA;AAAA,eAC5B;AAEA,cAAI,IAAA,CAAC,WAAY,CAAA,OAAO,CAAG,EAAA;AACzB,gBAAA,WAAA,CAAY,OAAO,CAAI,GAAA;AAAA,kBACrB,EAAI,EAAA,OAAA;AAAA,kBACJ,IAAM,EAAA,CAAA,EAAG,IAAK,CAAA,YAAY,IAAI,WAAW,CAAA,CAAA;AAAA,kBACzC,OAAA,EAAS,IAAK,CAAA,kBAAA,CAAmB,WAAW,CAAA;AAAA,kBAC5C,QAAA,EAAU,wBAAyB,CAAA,WAAA,EAAa,gBAAgB,CAAA;AAAA,kBAChE,UAAU,IAAK,CAAA,YAAA;AAAA,kBACf,SAAS,EAAC;AAAA,kBACV,GAAG,YAAA;AAAA,iBACL,CAAA;AAAA,eACF;AAEA,cAAA,IAAI,CAACF,uBAAA,CAAO,IAAI,CAAA,CAAE,QAAS,CAAAA,uBAAA,CAAO,QAAS,CAAA,KAAA,CAAM,SAAW,EAAA,EAAE,CAAC,CAAC,CAAG,EAAA;AACjE,gBAAA,IAAI,KAAM,CAAA,WAAA,CAAY,WAAY,EAAA,KAAM,SAAW,EAAA;AACjD,kBAAA,MAAM,SAAY,GAAA,IAAA,CAAK,SAAU,CAAA,CAAA,EAAG,CAAC,CAAA,CAAA;AACrC,kBAAA,WAAA,CAAY,OAAO,CAAE,CAAA,OAAA,CAAQ,SAAS,CAAA,GAAI,WAAW,IAAI,CAAA,CAAA;AAAA,iBACpD,MAAA;AACL,kBAAA,WAAA,CAAY,OAAO,CAAE,CAAA,OAAA,CAAQ,IAAI,CAAA,GAAI,WAAW,IAAI,CAAA,CAAA;AAAA,iBACtD;AAAA,eACF;AACA,cAAO,OAAA,WAAA,CAAA;AAAA,aACT;AAAA,YACA,EAAC;AAAA,WACH,CAAA;AAGA,UAAM,MAAA,iBAAA;AAAA,YACJ,IAAK,CAAA,KAAA;AAAA,YACL,MAAA,CAAO,OAAO,eAAe,CAAA;AAAA,YAC7B,IAAK,CAAA,YAAA;AAAA,YACL,WAAA;AAAA,YACA,KAAA;AAAA,YACA,EAAA,GAAK,KAAK,CAAI,GAAA,GAAA;AAAA,WAChB,CAAA;AAEA,UAAA,MAAA,CAAO,MAAO,CAAA,eAAe,CAAE,CAAA,GAAA,CAAI,CAAC,KAAkB,KAAA;AACpD,YAAA,OAAA,CAAQ,KAAK,KAAK,CAAA,CAAA;AAAA,WACnB,CAAA,CAAA;AAAA,iBACM,CAAG,EAAA;AACV,UAAK,IAAA,CAAA,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA;AACnB,UAAA,MAAA,CAAO,IAAK,CAAA;AAAA,YACV,UAAU,IAAK,CAAA,YAAA;AAAA,YACf,IAAM,EAAA,CAAA,EAAG,IAAK,CAAA,YAAY,IAAI,WAAW,CAAA,CAAA;AAAA,YACzC,OAAO,CAAE,CAAA,OAAA;AAAA,WACV,CAAA,CAAA;AAAA,SACH;AAAA,OACC,GAAA,CAAA;AACH,MAAA,QAAA,CAAS,KAAK,OAAO,CAAA,CAAA;AAAA,KACvB;AACA,IAAM,MAAA,OAAA,CAAQ,IAAI,QAAQ,CAAA,CAAA;AAC1B,IAAO,OAAA;AAAA,MACL,OAAS,EAAA,OAAA;AAAA,MACT,MAAA;AAAA,KACF,CAAA;AAAA,GACF;AACF;;AC3PO,MAAM,SAAoC,CAAA;AAAA,EAK/C,WACmB,CAAA,YAAA,EACA,MACA,EAAA,QAAA,EACA,OACA,MACjB,EAAA;AALiB,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA,CAAA;AACA,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AAAA,GAChB;AAAA,EAVH,OAAO,MAAA,CAAO,MAAgB,EAAA,QAAA,EAA2B,OAAqB,MAAuB,EAAA;AACnG,IAAA,OAAO,IAAI,SAAU,CAAA,KAAA,EAAO,MAAQ,EAAA,QAAA,EAAU,OAAO,MAAM,CAAA,CAAA;AAAA,GAC7D;AAAA,EAUA,mBAAmB,WAA6B,EAAA;AAC9C,IAAA,IAAI,aAAgB,GAAA,WAAA,CAAA;AAEpB,IAAM,MAAA,QAAA,GAAW,CAAC,cAAc,CAAA,CAAA;AAEhC,IAAA,KAAA,MAAW,UAAU,QAAU,EAAA;AAC7B,MAAI,IAAA,WAAA,CAAY,UAAW,CAAA,MAAM,CAAG,EAAA;AAClC,QAAA,aAAA,GAAgB,WAAY,CAAA,KAAA,CAAM,MAAO,CAAA,MAAM,EAAE,IAAK,EAAA,CAAA;AAAA,OACxD;AAAA,KACF;AAEA,IAAA,OAAO,CAAG,EAAA,IAAA,CAAK,YAAY,CAAA,CAAA,EAAI,aAAa,CAAA,CAAA,CAAA;AAAA,GAC9C;AAAA,EAEA,MAAM,aAAc,CAAA,WAAA,EAAqB,SAAmB,EAAA,SAAA,EAAmB,SAAiB,KAAkB,EAAA;AAEhH,IAAA,MAAM,OAAU,GAAA;AAAA,MACd,WAAa,EAAA,WAAA;AAAA,MACb,SAAA;AAAA,KACF,CAAA;AAGA,IAAM,MAAAQ,UAAA,GAAW,IAAIC,iBAAA,CAAS,OAAO,CAAA,CAAA;AACrC,IAAI,IAAA;AACF,MAAA,MAAM,eAAe,KAAM,CAAA,WAAA,CAAY,WAAY,EAAA,KAAM,YAAY,OAAU,GAAA,UAAA,CAAA;AAC/E,MAAA,MAAM,GAAM,GAAA,CAAA;AAAA;AAAA;AAAA;AAAA,4BAAA,EAIY,YAAY,CAAA;AAAA;AAAA;AAAA,YAAA,EAG5B,SAAS,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAAI,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA,mDAAA,EAIM,MAAM,SAAS,CAAA;AAAA,mDAAA,EACf,MAAM,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA,0CAAA,CAAA,CAAA;AAO5D,MAAA,MAAM,CAAC,GAAG,CAAI,GAAA,MAAMD,WAAS,cAAe,CAAA;AAAA,QAC1C,KAAO,EAAA,GAAA;AAAA,QACP,QAAU,EAAA,IAAA;AAAA,OACX,CAAA,CAAA;AAGD,MAAA,MAAM,CAAC,IAAI,CAAI,GAAA,MAAM,IAAI,eAAgB,EAAA,CAAA;AAEzC,MAAO,OAAA,IAAA,CAAA;AAAA,aACA,GAAK,EAAA;AACZ,MAAM,MAAA,IAAI,KAAM,CAAA,GAAA,CAAI,OAAO,CAAA,CAAA;AAAA,KAC7B;AAAA,GACF;AAAA,EAEA,MAAM,oBAAoB,KAA2C,EAAA;AACnE,IAAA,MAAM,IAAO,GAAA,IAAA,CAAK,MAAO,CAAA,sBAAA,CAAuB,sCAAsC,CAAA,CAAA;AACtF,IAAA,IAAI,CAAC,IAAM,EAAA;AACT,MAAA,OAAO,EAAE,OAAS,EAAA,EAAI,EAAA,MAAA,EAAQ,EAAG,EAAA,CAAA;AAAA,KACnC;AAEA,IAAA,MAAM,WAAW,EAAC,CAAA;AAClB,IAAA,MAAM,UAAoB,EAAC,CAAA;AAC3B,IAAA,MAAM,SAA+B,EAAC,CAAA;AAEtC,IAAA,KAAA,MAAW,KAAK,IAAM,EAAA;AACpB,MAAM,MAAA,WAAA,GAAc,CAAE,CAAA,SAAA,CAAU,MAAM,CAAA,CAAA;AAGtC,MAAM,MAAA,WAAA,GAAc,MAAM,mBAAoB,CAAA,IAAA,CAAK,OAAO,IAAK,CAAA,YAAA,EAAc,aAAa,KAAK,CAAA,CAAA;AAC/F,MAAA,IAAI,WAAa,EAAA;AACf,QAAA,IAAA,CAAK,OAAO,KAAM,CAAA,CAAA,EAAG,KAAK,YAAY,CAAA,CAAA,EAAI,WAAW,CAAmB,iBAAA,CAAA,CAAA,CAAA;AACxE,QAAA,WAAA,CAAY,IAAI,CAAQ,IAAA,KAAA;AACtB,UAAA,OAAA,CAAQ,KAAK,IAAI,CAAA,CAAA;AAAA,SAClB,CAAA,CAAA;AACD,QAAA,SAAA;AAAA,OACF;AAEA,MAAM,MAAA,WAAA,GAAc,CAAE,CAAA,SAAA,CAAU,aAAa,CAAA,CAAA;AAC7C,MAAM,MAAA,SAAA,GAAY,CAAE,CAAA,SAAA,CAAU,WAAW,CAAA,CAAA;AACzC,MAAM,MAAA,SAAA,GAAY,CAAE,CAAA,SAAA,CAAU,WAAW,CAAA,CAAA;AACzC,MAAM,MAAA,OAAA,GAAU,CAAE,CAAA,SAAA,CAAU,SAAS,CAAA,CAAA;AACrC,MAAM,MAAA,IAAA,GAAO,CAAE,CAAA,sBAAA,CAAuB,MAAM,CAAA,CAAA;AAC5C,MAAA,MAAM,eAA0C,EAAC,CAAA;AACjD,MAAA,IAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,IAAA,CAAM,QAAQ,CAAO,GAAA,KAAA;AACnB,QAAA,MAAM,CAAC,CAAG,EAAA,CAAC,CAAI,GAAA,GAAA,CAAI,MAAM,GAAG,CAAA,CAAA;AAC5B,QAAA,YAAA,CAAa,CAAE,CAAA,IAAA,EAAM,CAAA,GAAI,EAAE,IAAK,EAAA,CAAA;AAAA,OAClC,CAAA,CAAA;AACA,MAAA,MAAM,mBAAmB,MAAM,mBAAA,CAAoB,IAAK,CAAA,QAAA,EAAU,KAAK,YAAY,CAAA,CAAA;AAEnF,MAAA,MAAM,WAAW,YAAY;AAC3B,QAAI,IAAA;AACF,UAAM,MAAA,YAAA,GAAe,MAAM,IAAK,CAAA,aAAA,CAAc,aAAa,SAAW,EAAA,SAAA,EAAW,SAAS,KAAK,CAAA,CAAA;AAC/F,UAAA,MAAM,eAAkB,GAAAN,aAAA;AAAA,YACtB,YAAA;AAAA,YACA,CAAC,KAAgC,GAAQ,KAAA;AACvC,cAAA,MAAM,SAAS,GAAI,CAAA,MAAA,CAAA;AACnB,cAAM,MAAA,OAAA,GAAU,GAAG,WAAW,CAAA,CAAA,EAAI,IAAI,OAAO,CAAA,CAAA,EAAI,IAAI,OAAO,CAAA,CAAA,CAAA;AAE5D,cAAI,IAAA,CAAC,GAAI,CAAA,OAAO,CAAG,EAAA;AACjB,gBAAA,GAAA,CAAI,OAAO,CAAI,GAAA;AAAA,kBACb,EAAI,EAAA,OAAA;AAAA,kBACJ,IAAM,EAAA,CAAA,EAAG,IAAK,CAAA,YAAY,IAAI,WAAW,CAAA,CAAA;AAAA,kBACzC,OAAS,EAAA,IAAA,CAAK,kBAAmB,CAAA,GAAA,CAAI,OAAO,CAAA;AAAA,kBAC5C,QAAU,EAAA,wBAAA,CAAyB,GAAI,CAAA,OAAA,EAAS,gBAAgB,CAAA;AAAA,kBAChE,UAAU,IAAK,CAAA,YAAA;AAAA,kBACf,SAAS,EAAC;AAAA,kBACV,GAAG,EAAE,OAAS,EAAA,GAAA,CAAI,OAAQ,EAAA;AAAA;AAAA,kBAC1B,GAAG,YAAA;AAAA;AAAA,iBACL,CAAA;AAAA,eACF;AAEA,cAAA,GAAA,CAAI,OAAO,CAAA,CAAE,OAAQ,CAAA,MAAM,IAAI,GAAI,CAAA,UAAA,CAAA;AAEnC,cAAO,OAAA,GAAA,CAAA;AAAA,aACT;AAAA,YACA,EAAC;AAAA,WACH,CAAA;AAGA,UAAM,MAAA,iBAAA;AAAA,YACJ,IAAK,CAAA,KAAA;AAAA,YACL,MAAA,CAAO,OAAO,eAAe,CAAA;AAAA,YAC7B,IAAK,CAAA,YAAA;AAAA,YACL,WAAA;AAAA,YACA,KAAA;AAAA,YACA,EAAA,GAAK,KAAK,CAAI,GAAA,GAAA;AAAA,WAChB,CAAA;AAEA,UAAA,MAAA,CAAO,MAAO,CAAA,eAAe,CAAE,CAAA,GAAA,CAAI,CAAC,KAAe,KAAA;AACjD,YAAA,OAAA,CAAQ,KAAK,KAAK,CAAA,CAAA;AAAA,WACnB,CAAA,CAAA;AAAA,iBACM,CAAG,EAAA;AACV,UAAK,IAAA,CAAA,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA;AACnB,UAAA,MAAA,CAAO,IAAK,CAAA;AAAA,YACV,UAAU,IAAK,CAAA,YAAA;AAAA,YACf,IAAM,EAAA,CAAA,EAAG,IAAK,CAAA,YAAY,IAAI,WAAW,CAAA,CAAA;AAAA,YACzC,OAAO,CAAE,CAAA,OAAA;AAAA,WACV,CAAA,CAAA;AAAA,SACH;AAAA,OACC,GAAA,CAAA;AACH,MAAA,QAAA,CAAS,KAAK,OAAO,CAAA,CAAA;AAAA,KACvB;AACA,IAAM,MAAA,OAAA,CAAQ,IAAI,QAAQ,CAAA,CAAA;AAC1B,IAAO,OAAA;AAAA,MACL,OAAS,EAAA,OAAA;AAAA,MACT,MAAA;AAAA,KACF,CAAA;AAAA,GACF;AACF;;AC3JA,eAAe,cAAc,QAA2B,EAAA;AAlBxD,EAAA,IAAA,EAAA,CAAA;AAoBE,EAAM,MAAA,MAAA,GAAS,MAAM,QAAA,CAAS,SAAU,EAAA,CAAA;AACxC,EAAM,MAAA,aAAA,GAAgBQ,mCAAmB,CAAA,4CAAA,EAA8C,YAAY,CAAA,CAAA;AACnG,EAAA,IAAI,EAAC,CAAA,EAAA,GAAA,QAAA,CAAS,UAAT,KAAA,IAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAqB,IAAM,CAAA,EAAA;AAC9B,IAAM,MAAA,MAAA,CAAO,QAAQ,MAAO,CAAA;AAAA,MAC1B,SAAW,EAAA,aAAA;AAAA,KACZ,CAAA,CAAA;AAAA,GACH;AAGA,EAAM,MAAA,QAAA,GAAWA,mCAAmB,CAAA,4CAAA,EAA8C,OAAO,CAAA,CAAA;AACzF,EAAA,MAAM,OAAO,IAAK,CAAA,GAAA,CAAI,EAAE,SAAA,EAAW,UAAU,CAAA,CAAA;AAC/C,CAAA;AAEA,eAAsB,aAAa,OAAiD,EAAA;AAClF,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAQ,EAAA,KAAA,EAAO,UAAa,GAAA,OAAA,CAAA;AAE5C,EAAA,MAAM,cAAc,QAAQ,CAAA,CAAA;AAE5B,EAAA,MAAM,SAASC,uBAAO,EAAA,CAAA;AACtB,EAAO,MAAA,CAAA,GAAA,CAAIC,wBAAQ,CAAA,IAAA,EAAM,CAAA,CAAA;AAEzB,EAAA,MAAM,cAAc,WAAY,CAAA,MAAA,CAAO,MAAQ,EAAA,QAAA,EAAU,OAAO,MAAM,CAAA,CAAA;AACtE,EAAA,MAAM,YAAY,SAAU,CAAA,MAAA,CAAO,MAAQ,EAAA,QAAA,EAAU,OAAO,MAAM,CAAA,CAAA;AAClE,EAAA,MAAM,YAAY,SAAU,CAAA,MAAA,CAAO,MAAQ,EAAA,QAAA,EAAU,OAAO,MAAM,CAAA,CAAA;AAClE,EAAA,MAAM,YAAiC,GAAA,CAAC,WAAa,EAAA,SAAA,EAAW,SAAS,CAAA,CAAA;AAEzE,EAAA,MAAA,CAAO,GAAI,CAAA,SAAA,EAAW,CAAC,CAAA,EAAG,QAAa,KAAA;AACrC,IAAA,MAAA,CAAO,KAAK,OAAO,CAAA,CAAA;AACnB,IAAA,QAAA,CAAS,IAAK,CAAA,EAAE,MAAQ,EAAA,IAAA,EAAM,CAAA,CAAA;AAAA,GAC/B,CAAA,CAAA;AAED,EAAA,MAAA,CAAO,GAAI,CAAA,UAAA,EAAY,OAAO,OAAA,EAAS,QAAa,KAAA;AAClD,IAAM,MAAA,OAAA,GAAU,QAAQ,KAAM,CAAA,OAAA,CAAA;AAC9B,IAAM,MAAA,MAAA,GAAS,QAAQ,KAAM,CAAA,MAAA,CAAA;AAC7B,IAAM,MAAA,WAAA,GAAc,QAAQ,KAAM,CAAA,WAAA,CAAA;AAClC,IAAM,MAAA,SAAA,GAAY,QAAQ,KAAM,CAAA,SAAA,CAAA;AAChC,IAAM,MAAA,OAAA,GAAU,QAAQ,KAAM,CAAA,OAAA,CAAA;AAC9B,IAAA,MAAM,WAA4B,EAAC,CAAA;AACnC,IAAA,MAAM,UAAoB,EAAC,CAAA;AAC3B,IAAA,MAAM,SAA+B,EAAC,CAAA;AAEtC,IAAa,YAAA,CAAA,OAAA,CAAQ,OAAM,MAAU,KAAA;AACnC,MAAA,MAAM,mBAAmB,YAAY;AACnC,QAAI,IAAA;AACF,UAAM,MAAA,cAAA,GAAiB,MAAM,MAAA,CAAO,mBAAoB,CAAA;AAAA,YACtD,OAAA;AAAA,YACA,MAAA;AAAA,YACA,WAAA;AAAA,YACA,SAAA;AAAA,YACA,OAAA;AAAA,WACD,CAAA,CAAA;AACD,UAAe,cAAA,CAAA,MAAA,CAAO,QAAQ,CAAK,CAAA,KAAA;AACjC,YAAA,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA;AAAA,WACd,CAAA,CAAA;AACD,UAAe,cAAA,CAAA,OAAA,CAAQ,QAAQ,CAAQ,IAAA,KAAA;AACrC,YAAA,OAAA,CAAQ,KAAK,IAAI,CAAA,CAAA;AAAA,WAClB,CAAA,CAAA;AAAA,iBACM,CAAG,EAAA;AACV,UAAA,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA;AACd,UAAA,MAAA,CAAO,IAAK,CAAA;AAAA,YACV,QAAA,EAAU,OAAO,WAAY,CAAA,IAAA;AAAA,YAC7B,IAAA,EAAM,OAAO,WAAY,CAAA,IAAA;AAAA,YACzB,OAAO,CAAE,CAAA,OAAA;AAAA,WACV,CAAA,CAAA;AAAA,SACH;AAAA,OACC,GAAA,CAAA;AACH,MAAA,QAAA,CAAS,KAAK,eAAe,CAAA,CAAA;AAAA,KAC9B,CAAA,CAAA;AAED,IAAM,MAAA,OAAA,CAAQ,IAAI,QAAQ,CAAA,CAAA;AAE1B,IAAI,IAAA,MAAA,CAAO,SAAS,CAAG,EAAA;AACrB,MAAS,QAAA,CAAA,MAAA,CAAO,GAAG,CAAA,CAAE,IAAK,CAAA,EAAE,MAAM,OAAS,EAAA,MAAA,EAAgB,MAAQ,EAAA,GAAA,EAAK,CAAA,CAAA;AAAA,KACnE,MAAA;AACL,MAAA,QAAA,CAAS,KAAK,EAAE,IAAA,EAAM,SAAS,MAAgB,EAAA,MAAA,EAAQ,KAAK,CAAA,CAAA;AAAA,KAC9D;AAAA,GACD,CAAA,CAAA;AAED,EAAO,MAAA,CAAA,GAAA,CAAIC,4BAAc,CAAA,CAAA;AACzB,EAAO,OAAA,MAAA,CAAA;AACT;;AC5FO,MAAM,oBAAoBC,oCAAoB,CAAA;AAAA,EACnD,QAAU,EAAA,aAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,YAAYC,6BAAa,CAAA,UAAA;AAAA,QACzB,QAAQA,6BAAa,CAAA,MAAA;AAAA,QACrB,QAAQA,6BAAa,CAAA,UAAA;AAAA,QACrB,OAAOA,6BAAa,CAAA,KAAA;AAAA,QACpB,UAAUA,6BAAa,CAAA,QAAA;AAAA,OACzB;AAAA,MACA,MAAM,KAAK,EAAE,UAAA,EAAY,QAAQ,MAAQ,EAAA,KAAA,EAAO,UAAY,EAAA;AAC1D,QAAW,UAAA,CAAA,GAAA;AAAA,UACT,MAAM,YAAa,CAAA;AAAA,YACjB,MAAA;AAAA,YACA,MAAA;AAAA,YACA,KAAA;AAAA,YACA,QAAA;AAAA,WACD,CAAA;AAAA,SACH,CAAA;AACA,QAAA,UAAA,CAAW,aAAc,CAAA;AAAA,UACvB,IAAM,EAAA,SAAA;AAAA,UACN,KAAO,EAAA,iBAAA;AAAA,SACR,CAAA,CAAA;AAAA,OACH;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACF,CAAC;;;;;"}
@@ -11,28 +11,13 @@ exports.up = async function up(knex) {
11
11
  // category mappings
12
12
  //
13
13
  .createTable('category_mappings', table => {
14
- table.comment(
15
- 'Category mapping configurations for different cloud service names',
16
- );
17
- table
18
- .uuid('id')
19
- .defaultTo(knex.fn.uuid())
20
- .primary()
21
- .notNullable()
22
- .comment('Auto-generated ID of a mapping');
23
- table
24
- .string('provider')
25
- .notNullable()
26
- .comment('The name of a cloud provider');
27
- table
28
- .string('category')
29
- .notNullable()
30
- .comment('The name of a category');
14
+ table.comment('Category mapping configurations for different cloud service names');
15
+ table.uuid('id').defaultTo(knex.fn.uuid()).primary().notNullable().comment('Auto-generated ID of a mapping');
16
+ table.string('provider').notNullable().comment('The name of a cloud provider');
17
+ table.string('category').notNullable().comment('The name of a category');
31
18
  table
32
19
  .json('cloud_service_names') // if a database such as sqlite does not support json column, the data will be stored as plain text
33
- .comment(
34
- 'The cloud services that belong to this category (in json format like `["service1", "service2"]`)',
35
- );
20
+ .comment('The cloud services that belong to this category (in json format like `["service1", "service2"]`)');
36
21
  })
37
22
  );
38
23
  };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @param { import("knex").Knex } knex
3
+ * @returns { Promise<void> }
4
+ */
5
+ exports.up = async function up(knex) {
6
+ await knex.schema
7
+ //
8
+ // category mappings
9
+ //
10
+ .createTable('category_mappings_default', table => {
11
+ table.comment(
12
+ 'Default category mapping configurations for different cloud service names (records are recreated everytime when InfraWallet backend starts)',
13
+ );
14
+ table.uuid('id').defaultTo(knex.fn.uuid()).primary().notNullable().comment('Auto-generated ID of a mapping');
15
+ table.string('provider').notNullable().comment('The name of a cloud provider');
16
+ table.string('category').notNullable().comment('The name of a category');
17
+ table
18
+ .json('cloud_service_names') // if a database such as sqlite does not support json column, the data will be stored as plain text
19
+ .comment('The cloud services that belong to this category (in json format like `["service1", "service2"]`)');
20
+ });
21
+
22
+ await knex.schema
23
+ //
24
+ // category mappings
25
+ //
26
+ .createTable('category_mappings_override', table => {
27
+ table.comment('User-defined category mappings that can override the default ones');
28
+ table.uuid('id').defaultTo(knex.fn.uuid()).primary().notNullable().comment('Auto-generated ID of a mapping');
29
+ table.string('provider').notNullable().comment('The name of a cloud provider');
30
+ table.string('category').notNullable().comment('The name of a category');
31
+ table
32
+ .json('cloud_service_names') // if a database such as sqlite does not support json column, the data will be stored as plain text
33
+ .comment('The cloud services that belong to this category (in json format like `["service1", "service2"]`)');
34
+ });
35
+ };
36
+
37
+ /**
38
+ * @param { import("knex").Knex } knex
39
+ * @returns { Promise<void> }
40
+ */
41
+ exports.down = async function down(knex) {
42
+ await knex.schema.dropTableIfExists('category_mappings_default');
43
+ await knex.schema.dropTableIfExists('category_mappings_override');
44
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electrolux-oss/plugin-infrawallet-backend",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "backstage": {
5
5
  "role": "backend-plugin"
6
6
  },