@red-hat-developer-hub/plugin-cost-management-common 2.0.1 → 2.1.0

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.
@@ -45,7 +45,13 @@ class CostManagementSlimClient {
45
45
  method: "GET"
46
46
  });
47
47
  if (!response.ok) {
48
- throw new Error(response.statusText);
48
+ let message = response.statusText;
49
+ try {
50
+ const body = await response.json();
51
+ if (body.error) message = body.error;
52
+ } catch {
53
+ }
54
+ throw new Error(message);
49
55
  }
50
56
  const responseContentType = response.headers.get("content-type") || "";
51
57
  const responseText = await response.text();
@@ -341,7 +347,13 @@ class CostManagementSlimClient {
341
347
  method: "GET"
342
348
  });
343
349
  if (!response.ok) {
344
- throw new Error(response.statusText);
350
+ let message = response.statusText;
351
+ try {
352
+ const body = await response.json();
353
+ if (body.error) message = body.error;
354
+ } catch {
355
+ }
356
+ throw new Error(message);
345
357
  }
346
358
  return {
347
359
  ok: response.ok,
@@ -362,7 +374,13 @@ class CostManagementSlimClient {
362
374
  method: "GET"
363
375
  });
364
376
  if (!response.ok) {
365
- throw new Error(response.statusText);
377
+ let message = response.statusText;
378
+ try {
379
+ const body = await response.json();
380
+ if (body.error) message = body.error;
381
+ } catch {
382
+ }
383
+ throw new Error(message);
366
384
  }
367
385
  return {
368
386
  ...response,
@@ -1 +1 @@
1
- {"version":3,"file":"CostManagementSlimClient.cjs.js","sources":["../../../src/clients/cost-management/CostManagementSlimClient.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport crossFetch from 'cross-fetch';\nimport { pluginId } from '../../generated/pluginId';\nimport type { TypedResponse } from '../../generated/apis';\nimport type {\n CostManagementReport,\n GetCostManagementRequest,\n DownloadCostManagementRequest,\n} from './types';\nimport type { CostManagementSlimApi } from './CostManagementSlimApi';\n/**\n * Client for Cost Management data.\n *\n * In the frontend, requests are routed through the backend plugin's secure\n * proxy (`/api/cost-management/proxy/...`), which keeps the SSO token\n * server-side and enforces RBAC before forwarding to the Cost Management API.\n *\n * @public\n */\nexport class CostManagementSlimClient implements CostManagementSlimApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: { discoveryApi: DiscoveryApi; fetchApi?: FetchApi }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi ?? { fetch: crossFetch };\n }\n\n public async getCostManagementReport(\n request: GetCostManagementRequest,\n ): Promise<TypedResponse<CostManagementReport>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const uri = '/proxy/reports/openshift/costs/';\n\n const queryParams = this.buildCostManagementQueryParams(request);\n\n const queryString = queryParams.toString();\n const queryPart = queryString ? `?${queryString}` : '';\n const url = `${baseUrl}${uri}${queryPart}`;\n\n return await this.fetchViaBackendProxy<CostManagementReport>(url);\n }\n\n public async downloadCostManagementReport(\n request: DownloadCostManagementRequest,\n ): Promise<void> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const uri = '/proxy/reports/openshift/costs/';\n\n const downloadRequest: GetCostManagementRequest = {\n query: {\n ...request.query,\n 'filter[limit]': 0,\n },\n };\n delete downloadRequest.query['filter[offset]'];\n\n const queryParams = this.buildCostManagementQueryParams(downloadRequest);\n\n const queryString = queryParams.toString();\n const queryPart = queryString ? `?${queryString}` : '';\n const url = `${baseUrl}${uri}${queryPart}`;\n\n const acceptHeader =\n request.format === 'csv' ? 'text/csv' : 'application/json';\n\n const response = await this.fetchApi.fetch(url, {\n headers: {\n Accept: acceptHeader,\n },\n method: 'GET',\n });\n\n if (!response.ok) {\n throw new Error(response.statusText);\n }\n\n // Get the response data\n const responseContentType = response.headers.get('content-type') || '';\n const responseText = await response.text();\n\n let data: string;\n let mimeType: string;\n\n if (request.format === 'csv') {\n // User wants CSV - use response as-is (API returns CSV by default)\n data = responseText;\n mimeType = 'text/csv';\n } else {\n // User wants JSON\n if (responseContentType.includes('application/json')) {\n // Response is already JSON\n const jsonData = JSON.parse(responseText);\n data = JSON.stringify(jsonData, null, 2);\n } else {\n // Response is CSV, need to convert to JSON\n data = this.convertCsvToJson(responseText);\n }\n mimeType = 'application/json';\n }\n\n // Generate filename with timestamp\n const timestamp = new Date().toISOString().replaceAll(/[:.]/g, '-');\n const extension = request.format;\n const filename = `openshift-costs-${timestamp}.${extension}`;\n\n // Trigger download in browser\n const blob = new Blob([data], { type: mimeType });\n const downloadUrl = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = downloadUrl;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n link.remove();\n URL.revokeObjectURL(downloadUrl);\n }\n\n /**\n * Converts CSV string to JSON string\n * @param csv - The CSV data as a string\n * @returns JSON string representation of the CSV data\n */\n private convertCsvToJson(csv: string): string {\n // Normalize line endings (handle both \\r\\n and \\r)\n const normalizedCsv = csv.replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n');\n const lines = normalizedCsv.trim().split('\\n');\n if (lines.length === 0) {\n return JSON.stringify({ data: [] }, null, 2);\n }\n\n const headers = this.parseCsvLine(lines[0]);\n const data: Record<string, string | number | null>[] = [];\n\n for (let i = 1; i < lines.length; i++) {\n const values = this.parseCsvLine(lines[i]);\n const row: Record<string, string | number | null> = {};\n\n for (let j = 0; j < headers.length; j++) {\n const header = headers[j];\n const value = values[j] || '';\n\n // Try to parse as number if it looks like one\n if (value === '') {\n row[header] = null;\n } else if (!Number.isNaN(Number(value)) && value !== '') {\n row[header] = Number(value);\n } else {\n row[header] = value;\n }\n }\n\n data.push(row);\n }\n\n return JSON.stringify({ data }, null, 2);\n }\n\n /**\n * Parses a CSV line handling quoted values\n * @param line - A single line from CSV\n * @returns Array of values\n */\n private parseCsvLine(line: string): string[] {\n const result: string[] = [];\n let current = '';\n let inQuotes = false;\n let skipNext = false;\n\n for (let i = 0; i < line.length; i++) {\n if (skipNext) {\n skipNext = false;\n continue;\n }\n\n const char = line[i];\n\n if (char === '\"') {\n if (inQuotes && line[i + 1] === '\"') {\n // Escaped quote\n current += '\"';\n skipNext = true;\n } else {\n // Toggle quote mode\n inQuotes = !inQuotes;\n }\n } else if (char === ',' && !inQuotes) {\n result.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n\n result.push(current);\n return result;\n }\n\n /**\n * Builds query parameters for cost management report request\n * @param request - The cost management request\n * @returns URLSearchParams with all query parameters\n */\n private buildCostManagementQueryParams(\n request: GetCostManagementRequest,\n ): URLSearchParams {\n const queryParams = new URLSearchParams();\n this.appendBasicQueryParams(queryParams, request);\n this.appendDynamicParams(queryParams, request, 'group_by[');\n this.appendDynamicParams(queryParams, request, 'order_by[');\n this.appendDynamicFilterParams(queryParams, request);\n this.appendDynamicExcludeParams(queryParams, request);\n return queryParams;\n }\n\n /**\n * Appends basic query parameters (currency, delta, and standard filters)\n */\n private appendBasicQueryParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n ): void {\n const basicParams: Array<{\n key: keyof typeof request.query;\n paramName: string;\n needsStringConversion?: boolean;\n }> = [\n { key: 'currency', paramName: 'currency' },\n { key: 'delta', paramName: 'delta' },\n { key: 'category', paramName: 'category' },\n {\n key: 'filter[limit]',\n paramName: 'filter[limit]',\n needsStringConversion: true,\n },\n {\n key: 'filter[offset]',\n paramName: 'filter[offset]',\n needsStringConversion: true,\n },\n { key: 'filter[resolution]', paramName: 'filter[resolution]' },\n {\n key: 'filter[time_scope_units]',\n paramName: 'filter[time_scope_units]',\n },\n {\n key: 'filter[time_scope_value]',\n paramName: 'filter[time_scope_value]',\n needsStringConversion: true,\n },\n {\n key: 'filter[exact:cluster]',\n paramName: 'filter[exact:cluster]',\n },\n ];\n\n for (const { key, paramName, needsStringConversion } of basicParams) {\n const value = request.query[key];\n if (value !== undefined && value !== null && value !== '') {\n queryParams.append(\n paramName,\n needsStringConversion ? String(value) : (value as string),\n );\n }\n }\n }\n\n /**\n * Appends dynamic parameters that match a specific prefix (e.g., 'group_by[', 'order_by[')\n */\n private appendDynamicParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n prefix: string,\n ): void {\n for (const key of Object.keys(request.query)) {\n if (key.startsWith(prefix) && key.endsWith(']')) {\n const value = request.query[key as keyof typeof request.query];\n if (value) {\n queryParams.append(key, String(value));\n }\n }\n }\n }\n\n /**\n * Appends dynamic filter parameters, excluding those already handled explicitly\n */\n private appendDynamicFilterParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n ): void {\n const handledFilterKeys = new Set([\n 'filter[limit]',\n 'filter[offset]',\n 'filter[resolution]',\n 'filter[time_scope_units]',\n 'filter[time_scope_value]',\n ]);\n\n for (const key of Object.keys(request.query)) {\n if (\n key.startsWith('filter[') &&\n key.endsWith(']') &&\n !handledFilterKeys.has(key)\n ) {\n const value = request.query[key as keyof typeof request.query];\n if (value) {\n queryParams.append(key, String(value));\n }\n }\n }\n }\n\n /**\n * Appends dynamic exclude parameters (e.g., exclude[project], exclude[cluster], exclude[tag:key])\n */\n private appendDynamicExcludeParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n ): void {\n for (const key of Object.keys(request.query)) {\n if (key.startsWith('exclude[') && key.endsWith(']')) {\n const value = request.query[key as keyof typeof request.query];\n if (value) {\n queryParams.append(key, String(value));\n }\n }\n }\n }\n\n /**\n * Search OpenShift projects\n * @param search - Search term to filter projects\n * @param options - Optional request options including token and limit\n * @param options.token - Bearer token for authentication (backend use)\n * @param options.limit - Maximum number of results to return (default: 10, use large number for all)\n */\n public async searchOpenShiftProjects(\n search: string = '',\n options?: { token?: string; limit?: number },\n ): Promise<\n TypedResponse<{ data: Array<{ value: string }>; meta?: any; links?: any }>\n > {\n const url = await this.buildResourceTypeUrl(\n 'openshift-projects',\n search,\n options?.limit,\n );\n\n // If token provided externally (backend use), use it directly\n if (options?.token) {\n return await this.fetchWithExternalToken(url, options.token);\n }\n\n // If no external token, use internal token retrieval\n return await this.fetchResourceType(url);\n }\n\n /**\n * Search OpenShift clusters\n * @param search - Search term to filter clusters\n */\n public async searchOpenShiftClusters(\n search: string = '',\n options?: { token?: string; limit?: number },\n ): Promise<\n TypedResponse<{\n data: Array<{ value: string; cluster_alias: string }>;\n meta?: any;\n links?: any;\n }>\n > {\n const url = await this.buildResourceTypeUrl(\n 'openshift-clusters',\n search,\n options?.limit,\n );\n\n // If token provided externally (backend use), use it directly\n if (options?.token) {\n return await this.fetchWithExternalToken(url, options.token);\n }\n\n // If no external token, use internal token retrieval\n return await this.fetchResourceType(url);\n }\n\n /**\n * Search OpenShift nodes\n * @param search - Search term to filter nodes\n */\n public async searchOpenShiftNodes(\n search: string = '',\n ): Promise<\n TypedResponse<{ data: Array<{ value: string }>; meta?: any; links?: any }>\n > {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const searchParam = search ? `?search=${encodeURIComponent(search)}` : '';\n const url = `${baseUrl}/proxy/resource-types/openshift-nodes/${searchParam}`;\n\n return await this.fetchResourceType(url);\n }\n\n /**\n * Get OpenShift tags\n * @param timeScopeValue - Time scope value (-1 for month-to-date, -2 for previous-month). Defaults to -1.\n * @returns TypedResponse with array of tag strings\n */\n public async getOpenShiftTags(\n timeScopeValue: number = -1,\n ): Promise<TypedResponse<{ data: string[]; meta?: any; links?: any }>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const url = `${baseUrl}/proxy/tags/openshift/?filter[time_scope_value]=${timeScopeValue}&key_only=true&limit=1000`;\n\n return await this.fetchViaBackendProxy<{\n data: string[];\n meta?: any;\n links?: any;\n }>(url);\n }\n\n /**\n * Get OpenShift tag values for a specific tag key\n * @param tagKey - The tag key to get values for\n * @param timeScopeValue - Time scope value (-1 for month-to-date, -2 for previous-month). Defaults to -1.\n * @returns TypedResponse with array of tag value objects\n */\n public async getOpenShiftTagValues(\n tagKey: string,\n timeScopeValue: number = -1,\n ): Promise<\n TypedResponse<{\n data: Array<{ key: string; values: string[]; enabled: boolean }>;\n meta?: any;\n links?: any;\n }>\n > {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const url = `${baseUrl}/proxy/tags/openshift/?filter[key]=${encodeURIComponent(\n tagKey,\n )}&filter[time_scope_value]=${timeScopeValue}`;\n\n return await this.fetchViaBackendProxy<{\n data: Array<{ key: string; values: string[]; enabled: boolean }>;\n meta?: any;\n links?: any;\n }>(url);\n }\n\n private async fetchResourceType(url: string): Promise<\n TypedResponse<{\n data: Array<{ value: string; cluster_alias: string }>;\n meta?: any;\n links?: any;\n }>\n > {\n return await this.fetchViaBackendProxy<{\n data: Array<{ value: string; cluster_alias: string }>;\n meta?: any;\n links?: any;\n }>(url);\n }\n\n /**\n * Builds resource type URL routed through the backend secure proxy\n */\n private async buildResourceTypeUrl(\n resourceType: string,\n search?: string,\n limit?: number,\n ): Promise<string> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n\n const params = new URLSearchParams();\n if (search) {\n params.append('search', search);\n }\n if (limit !== undefined) {\n params.append('limit', String(limit));\n }\n const queryString = params.toString();\n const queryPart = queryString ? `?${queryString}` : '';\n\n return `${baseUrl}/proxy/resource-types/${resourceType}/${queryPart}`;\n }\n\n /**\n * Fetches with externally provided token (for backend use).\n * This path bypasses the secure proxy since it's already server-side.\n */\n private async fetchWithExternalToken<T>(\n url: string,\n token: string,\n ): Promise<TypedResponse<T>> {\n const response = await this.fetchApi.fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n method: 'GET',\n });\n\n if (!response.ok) {\n throw new Error(response.statusText);\n }\n\n return {\n ok: response.ok,\n status: response.status,\n json: async () => response.json(),\n } as TypedResponse<T>;\n }\n\n /**\n * Fetches a URL via the backend secure proxy. No Authorization header\n * is sent; the backend injects the SSO token and RBAC filters\n * server-side. Authentication is via the Backstage session cookie.\n */\n private async fetchViaBackendProxy<T>(\n url: string,\n ): Promise<TypedResponse<T>> {\n const response = await this.fetchApi.fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'GET',\n });\n\n if (!response.ok) {\n throw new Error(response.statusText);\n }\n\n return {\n ...response,\n json: async () => {\n const data = (await response.json()) as T;\n return data;\n },\n };\n }\n}\n"],"names":["crossFetch","pluginId"],"mappings":"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"}
1
+ {"version":3,"file":"CostManagementSlimClient.cjs.js","sources":["../../../src/clients/cost-management/CostManagementSlimClient.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport crossFetch from 'cross-fetch';\nimport { pluginId } from '../../generated/pluginId';\nimport type { TypedResponse } from '../../generated/apis';\nimport type {\n CostManagementReport,\n GetCostManagementRequest,\n DownloadCostManagementRequest,\n} from './types';\nimport type { CostManagementSlimApi } from './CostManagementSlimApi';\n/**\n * Client for Cost Management data.\n *\n * In the frontend, requests are routed through the backend plugin's secure\n * proxy (`/api/cost-management/proxy/...`), which keeps the SSO token\n * server-side and enforces RBAC before forwarding to the Cost Management API.\n *\n * @public\n */\nexport class CostManagementSlimClient implements CostManagementSlimApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: { discoveryApi: DiscoveryApi; fetchApi?: FetchApi }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi ?? { fetch: crossFetch };\n }\n\n public async getCostManagementReport(\n request: GetCostManagementRequest,\n ): Promise<TypedResponse<CostManagementReport>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const uri = '/proxy/reports/openshift/costs/';\n\n const queryParams = this.buildCostManagementQueryParams(request);\n\n const queryString = queryParams.toString();\n const queryPart = queryString ? `?${queryString}` : '';\n const url = `${baseUrl}${uri}${queryPart}`;\n\n return await this.fetchViaBackendProxy<CostManagementReport>(url);\n }\n\n public async downloadCostManagementReport(\n request: DownloadCostManagementRequest,\n ): Promise<void> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const uri = '/proxy/reports/openshift/costs/';\n\n const downloadRequest: GetCostManagementRequest = {\n query: {\n ...request.query,\n 'filter[limit]': 0,\n },\n };\n delete downloadRequest.query['filter[offset]'];\n\n const queryParams = this.buildCostManagementQueryParams(downloadRequest);\n\n const queryString = queryParams.toString();\n const queryPart = queryString ? `?${queryString}` : '';\n const url = `${baseUrl}${uri}${queryPart}`;\n\n const acceptHeader =\n request.format === 'csv' ? 'text/csv' : 'application/json';\n\n const response = await this.fetchApi.fetch(url, {\n headers: {\n Accept: acceptHeader,\n },\n method: 'GET',\n });\n\n if (!response.ok) {\n let message = response.statusText;\n try {\n const body = (await response.json()) as any;\n if (body.error) message = body.error;\n } catch {\n // response may not be JSON\n }\n throw new Error(message);\n }\n\n // Get the response data\n const responseContentType = response.headers.get('content-type') || '';\n const responseText = await response.text();\n\n let data: string;\n let mimeType: string;\n\n if (request.format === 'csv') {\n // User wants CSV - use response as-is (API returns CSV by default)\n data = responseText;\n mimeType = 'text/csv';\n } else {\n // User wants JSON\n if (responseContentType.includes('application/json')) {\n // Response is already JSON\n const jsonData = JSON.parse(responseText);\n data = JSON.stringify(jsonData, null, 2);\n } else {\n // Response is CSV, need to convert to JSON\n data = this.convertCsvToJson(responseText);\n }\n mimeType = 'application/json';\n }\n\n // Generate filename with timestamp\n const timestamp = new Date().toISOString().replaceAll(/[:.]/g, '-');\n const extension = request.format;\n const filename = `openshift-costs-${timestamp}.${extension}`;\n\n // Trigger download in browser\n const blob = new Blob([data], { type: mimeType });\n const downloadUrl = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = downloadUrl;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n link.remove();\n URL.revokeObjectURL(downloadUrl);\n }\n\n /**\n * Converts CSV string to JSON string\n * @param csv - The CSV data as a string\n * @returns JSON string representation of the CSV data\n */\n private convertCsvToJson(csv: string): string {\n // Normalize line endings (handle both \\r\\n and \\r)\n const normalizedCsv = csv.replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n');\n const lines = normalizedCsv.trim().split('\\n');\n if (lines.length === 0) {\n return JSON.stringify({ data: [] }, null, 2);\n }\n\n const headers = this.parseCsvLine(lines[0]);\n const data: Record<string, string | number | null>[] = [];\n\n for (let i = 1; i < lines.length; i++) {\n const values = this.parseCsvLine(lines[i]);\n const row: Record<string, string | number | null> = {};\n\n for (let j = 0; j < headers.length; j++) {\n const header = headers[j];\n const value = values[j] || '';\n\n // Try to parse as number if it looks like one\n if (value === '') {\n row[header] = null;\n } else if (!Number.isNaN(Number(value)) && value !== '') {\n row[header] = Number(value);\n } else {\n row[header] = value;\n }\n }\n\n data.push(row);\n }\n\n return JSON.stringify({ data }, null, 2);\n }\n\n /**\n * Parses a CSV line handling quoted values\n * @param line - A single line from CSV\n * @returns Array of values\n */\n private parseCsvLine(line: string): string[] {\n const result: string[] = [];\n let current = '';\n let inQuotes = false;\n let skipNext = false;\n\n for (let i = 0; i < line.length; i++) {\n if (skipNext) {\n skipNext = false;\n continue;\n }\n\n const char = line[i];\n\n if (char === '\"') {\n if (inQuotes && line[i + 1] === '\"') {\n // Escaped quote\n current += '\"';\n skipNext = true;\n } else {\n // Toggle quote mode\n inQuotes = !inQuotes;\n }\n } else if (char === ',' && !inQuotes) {\n result.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n\n result.push(current);\n return result;\n }\n\n /**\n * Builds query parameters for cost management report request\n * @param request - The cost management request\n * @returns URLSearchParams with all query parameters\n */\n private buildCostManagementQueryParams(\n request: GetCostManagementRequest,\n ): URLSearchParams {\n const queryParams = new URLSearchParams();\n this.appendBasicQueryParams(queryParams, request);\n this.appendDynamicParams(queryParams, request, 'group_by[');\n this.appendDynamicParams(queryParams, request, 'order_by[');\n this.appendDynamicFilterParams(queryParams, request);\n this.appendDynamicExcludeParams(queryParams, request);\n return queryParams;\n }\n\n /**\n * Appends basic query parameters (currency, delta, and standard filters)\n */\n private appendBasicQueryParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n ): void {\n const basicParams: Array<{\n key: keyof typeof request.query;\n paramName: string;\n needsStringConversion?: boolean;\n }> = [\n { key: 'currency', paramName: 'currency' },\n { key: 'delta', paramName: 'delta' },\n { key: 'category', paramName: 'category' },\n {\n key: 'filter[limit]',\n paramName: 'filter[limit]',\n needsStringConversion: true,\n },\n {\n key: 'filter[offset]',\n paramName: 'filter[offset]',\n needsStringConversion: true,\n },\n { key: 'filter[resolution]', paramName: 'filter[resolution]' },\n {\n key: 'filter[time_scope_units]',\n paramName: 'filter[time_scope_units]',\n },\n {\n key: 'filter[time_scope_value]',\n paramName: 'filter[time_scope_value]',\n needsStringConversion: true,\n },\n {\n key: 'filter[exact:cluster]',\n paramName: 'filter[exact:cluster]',\n },\n ];\n\n for (const { key, paramName, needsStringConversion } of basicParams) {\n const value = request.query[key];\n if (value !== undefined && value !== null && value !== '') {\n queryParams.append(\n paramName,\n needsStringConversion ? String(value) : (value as string),\n );\n }\n }\n }\n\n /**\n * Appends dynamic parameters that match a specific prefix (e.g., 'group_by[', 'order_by[')\n */\n private appendDynamicParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n prefix: string,\n ): void {\n for (const key of Object.keys(request.query)) {\n if (key.startsWith(prefix) && key.endsWith(']')) {\n const value = request.query[key as keyof typeof request.query];\n if (value) {\n queryParams.append(key, String(value));\n }\n }\n }\n }\n\n /**\n * Appends dynamic filter parameters, excluding those already handled explicitly\n */\n private appendDynamicFilterParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n ): void {\n const handledFilterKeys = new Set([\n 'filter[limit]',\n 'filter[offset]',\n 'filter[resolution]',\n 'filter[time_scope_units]',\n 'filter[time_scope_value]',\n ]);\n\n for (const key of Object.keys(request.query)) {\n if (\n key.startsWith('filter[') &&\n key.endsWith(']') &&\n !handledFilterKeys.has(key)\n ) {\n const value = request.query[key as keyof typeof request.query];\n if (value) {\n queryParams.append(key, String(value));\n }\n }\n }\n }\n\n /**\n * Appends dynamic exclude parameters (e.g., exclude[project], exclude[cluster], exclude[tag:key])\n */\n private appendDynamicExcludeParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n ): void {\n for (const key of Object.keys(request.query)) {\n if (key.startsWith('exclude[') && key.endsWith(']')) {\n const value = request.query[key as keyof typeof request.query];\n if (value) {\n queryParams.append(key, String(value));\n }\n }\n }\n }\n\n /**\n * Search OpenShift projects\n * @param search - Search term to filter projects\n * @param options - Optional request options including token and limit\n * @param options.token - Bearer token for authentication (backend use)\n * @param options.limit - Maximum number of results to return (default: 10, use large number for all)\n */\n public async searchOpenShiftProjects(\n search: string = '',\n options?: { token?: string; limit?: number },\n ): Promise<\n TypedResponse<{ data: Array<{ value: string }>; meta?: any; links?: any }>\n > {\n const url = await this.buildResourceTypeUrl(\n 'openshift-projects',\n search,\n options?.limit,\n );\n\n // If token provided externally (backend use), use it directly\n if (options?.token) {\n return await this.fetchWithExternalToken(url, options.token);\n }\n\n // If no external token, use internal token retrieval\n return await this.fetchResourceType(url);\n }\n\n /**\n * Search OpenShift clusters\n * @param search - Search term to filter clusters\n */\n public async searchOpenShiftClusters(\n search: string = '',\n options?: { token?: string; limit?: number },\n ): Promise<\n TypedResponse<{\n data: Array<{ value: string; cluster_alias: string }>;\n meta?: any;\n links?: any;\n }>\n > {\n const url = await this.buildResourceTypeUrl(\n 'openshift-clusters',\n search,\n options?.limit,\n );\n\n // If token provided externally (backend use), use it directly\n if (options?.token) {\n return await this.fetchWithExternalToken(url, options.token);\n }\n\n // If no external token, use internal token retrieval\n return await this.fetchResourceType(url);\n }\n\n /**\n * Search OpenShift nodes\n * @param search - Search term to filter nodes\n */\n public async searchOpenShiftNodes(\n search: string = '',\n ): Promise<\n TypedResponse<{ data: Array<{ value: string }>; meta?: any; links?: any }>\n > {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const searchParam = search ? `?search=${encodeURIComponent(search)}` : '';\n const url = `${baseUrl}/proxy/resource-types/openshift-nodes/${searchParam}`;\n\n return await this.fetchResourceType(url);\n }\n\n /**\n * Get OpenShift tags\n * @param timeScopeValue - Time scope value (-1 for month-to-date, -2 for previous-month). Defaults to -1.\n * @returns TypedResponse with array of tag strings\n */\n public async getOpenShiftTags(\n timeScopeValue: number = -1,\n ): Promise<TypedResponse<{ data: string[]; meta?: any; links?: any }>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const url = `${baseUrl}/proxy/tags/openshift/?filter[time_scope_value]=${timeScopeValue}&key_only=true&limit=1000`;\n\n return await this.fetchViaBackendProxy<{\n data: string[];\n meta?: any;\n links?: any;\n }>(url);\n }\n\n /**\n * Get OpenShift tag values for a specific tag key\n * @param tagKey - The tag key to get values for\n * @param timeScopeValue - Time scope value (-1 for month-to-date, -2 for previous-month). Defaults to -1.\n * @returns TypedResponse with array of tag value objects\n */\n public async getOpenShiftTagValues(\n tagKey: string,\n timeScopeValue: number = -1,\n ): Promise<\n TypedResponse<{\n data: Array<{ key: string; values: string[]; enabled: boolean }>;\n meta?: any;\n links?: any;\n }>\n > {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const url = `${baseUrl}/proxy/tags/openshift/?filter[key]=${encodeURIComponent(\n tagKey,\n )}&filter[time_scope_value]=${timeScopeValue}`;\n\n return await this.fetchViaBackendProxy<{\n data: Array<{ key: string; values: string[]; enabled: boolean }>;\n meta?: any;\n links?: any;\n }>(url);\n }\n\n private async fetchResourceType(url: string): Promise<\n TypedResponse<{\n data: Array<{ value: string; cluster_alias: string }>;\n meta?: any;\n links?: any;\n }>\n > {\n return await this.fetchViaBackendProxy<{\n data: Array<{ value: string; cluster_alias: string }>;\n meta?: any;\n links?: any;\n }>(url);\n }\n\n /**\n * Builds resource type URL routed through the backend secure proxy\n */\n private async buildResourceTypeUrl(\n resourceType: string,\n search?: string,\n limit?: number,\n ): Promise<string> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n\n const params = new URLSearchParams();\n if (search) {\n params.append('search', search);\n }\n if (limit !== undefined) {\n params.append('limit', String(limit));\n }\n const queryString = params.toString();\n const queryPart = queryString ? `?${queryString}` : '';\n\n return `${baseUrl}/proxy/resource-types/${resourceType}/${queryPart}`;\n }\n\n /**\n * Fetches with externally provided token (for backend use).\n * This path bypasses the secure proxy since it's already server-side.\n */\n private async fetchWithExternalToken<T>(\n url: string,\n token: string,\n ): Promise<TypedResponse<T>> {\n const response = await this.fetchApi.fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n method: 'GET',\n });\n\n if (!response.ok) {\n let message = response.statusText;\n try {\n const body = (await response.json()) as any;\n if (body.error) message = body.error;\n } catch {\n // response may not be JSON\n }\n throw new Error(message);\n }\n\n return {\n ok: response.ok,\n status: response.status,\n json: async () => response.json(),\n } as TypedResponse<T>;\n }\n\n /**\n * Fetches a URL via the backend secure proxy. No Authorization header\n * is sent; the backend injects the SSO token and RBAC filters\n * server-side. Authentication is via the Backstage session cookie.\n */\n private async fetchViaBackendProxy<T>(\n url: string,\n ): Promise<TypedResponse<T>> {\n const response = await this.fetchApi.fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'GET',\n });\n\n if (!response.ok) {\n let message = response.statusText;\n try {\n const body = (await response.json()) as any;\n if (body.error) message = body.error;\n } catch {\n // response may not be JSON\n }\n throw new Error(message);\n }\n\n return {\n ...response,\n json: async () => {\n const data = (await response.json()) as T;\n return data;\n },\n };\n }\n}\n"],"names":["crossFetch","pluginId"],"mappings":"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"}
@@ -39,7 +39,13 @@ class CostManagementSlimClient {
39
39
  method: "GET"
40
40
  });
41
41
  if (!response.ok) {
42
- throw new Error(response.statusText);
42
+ let message = response.statusText;
43
+ try {
44
+ const body = await response.json();
45
+ if (body.error) message = body.error;
46
+ } catch {
47
+ }
48
+ throw new Error(message);
43
49
  }
44
50
  const responseContentType = response.headers.get("content-type") || "";
45
51
  const responseText = await response.text();
@@ -335,7 +341,13 @@ class CostManagementSlimClient {
335
341
  method: "GET"
336
342
  });
337
343
  if (!response.ok) {
338
- throw new Error(response.statusText);
344
+ let message = response.statusText;
345
+ try {
346
+ const body = await response.json();
347
+ if (body.error) message = body.error;
348
+ } catch {
349
+ }
350
+ throw new Error(message);
339
351
  }
340
352
  return {
341
353
  ok: response.ok,
@@ -356,7 +368,13 @@ class CostManagementSlimClient {
356
368
  method: "GET"
357
369
  });
358
370
  if (!response.ok) {
359
- throw new Error(response.statusText);
371
+ let message = response.statusText;
372
+ try {
373
+ const body = await response.json();
374
+ if (body.error) message = body.error;
375
+ } catch {
376
+ }
377
+ throw new Error(message);
360
378
  }
361
379
  return {
362
380
  ...response,
@@ -1 +1 @@
1
- {"version":3,"file":"CostManagementSlimClient.esm.js","sources":["../../../src/clients/cost-management/CostManagementSlimClient.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport crossFetch from 'cross-fetch';\nimport { pluginId } from '../../generated/pluginId';\nimport type { TypedResponse } from '../../generated/apis';\nimport type {\n CostManagementReport,\n GetCostManagementRequest,\n DownloadCostManagementRequest,\n} from './types';\nimport type { CostManagementSlimApi } from './CostManagementSlimApi';\n/**\n * Client for Cost Management data.\n *\n * In the frontend, requests are routed through the backend plugin's secure\n * proxy (`/api/cost-management/proxy/...`), which keeps the SSO token\n * server-side and enforces RBAC before forwarding to the Cost Management API.\n *\n * @public\n */\nexport class CostManagementSlimClient implements CostManagementSlimApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: { discoveryApi: DiscoveryApi; fetchApi?: FetchApi }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi ?? { fetch: crossFetch };\n }\n\n public async getCostManagementReport(\n request: GetCostManagementRequest,\n ): Promise<TypedResponse<CostManagementReport>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const uri = '/proxy/reports/openshift/costs/';\n\n const queryParams = this.buildCostManagementQueryParams(request);\n\n const queryString = queryParams.toString();\n const queryPart = queryString ? `?${queryString}` : '';\n const url = `${baseUrl}${uri}${queryPart}`;\n\n return await this.fetchViaBackendProxy<CostManagementReport>(url);\n }\n\n public async downloadCostManagementReport(\n request: DownloadCostManagementRequest,\n ): Promise<void> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const uri = '/proxy/reports/openshift/costs/';\n\n const downloadRequest: GetCostManagementRequest = {\n query: {\n ...request.query,\n 'filter[limit]': 0,\n },\n };\n delete downloadRequest.query['filter[offset]'];\n\n const queryParams = this.buildCostManagementQueryParams(downloadRequest);\n\n const queryString = queryParams.toString();\n const queryPart = queryString ? `?${queryString}` : '';\n const url = `${baseUrl}${uri}${queryPart}`;\n\n const acceptHeader =\n request.format === 'csv' ? 'text/csv' : 'application/json';\n\n const response = await this.fetchApi.fetch(url, {\n headers: {\n Accept: acceptHeader,\n },\n method: 'GET',\n });\n\n if (!response.ok) {\n throw new Error(response.statusText);\n }\n\n // Get the response data\n const responseContentType = response.headers.get('content-type') || '';\n const responseText = await response.text();\n\n let data: string;\n let mimeType: string;\n\n if (request.format === 'csv') {\n // User wants CSV - use response as-is (API returns CSV by default)\n data = responseText;\n mimeType = 'text/csv';\n } else {\n // User wants JSON\n if (responseContentType.includes('application/json')) {\n // Response is already JSON\n const jsonData = JSON.parse(responseText);\n data = JSON.stringify(jsonData, null, 2);\n } else {\n // Response is CSV, need to convert to JSON\n data = this.convertCsvToJson(responseText);\n }\n mimeType = 'application/json';\n }\n\n // Generate filename with timestamp\n const timestamp = new Date().toISOString().replaceAll(/[:.]/g, '-');\n const extension = request.format;\n const filename = `openshift-costs-${timestamp}.${extension}`;\n\n // Trigger download in browser\n const blob = new Blob([data], { type: mimeType });\n const downloadUrl = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = downloadUrl;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n link.remove();\n URL.revokeObjectURL(downloadUrl);\n }\n\n /**\n * Converts CSV string to JSON string\n * @param csv - The CSV data as a string\n * @returns JSON string representation of the CSV data\n */\n private convertCsvToJson(csv: string): string {\n // Normalize line endings (handle both \\r\\n and \\r)\n const normalizedCsv = csv.replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n');\n const lines = normalizedCsv.trim().split('\\n');\n if (lines.length === 0) {\n return JSON.stringify({ data: [] }, null, 2);\n }\n\n const headers = this.parseCsvLine(lines[0]);\n const data: Record<string, string | number | null>[] = [];\n\n for (let i = 1; i < lines.length; i++) {\n const values = this.parseCsvLine(lines[i]);\n const row: Record<string, string | number | null> = {};\n\n for (let j = 0; j < headers.length; j++) {\n const header = headers[j];\n const value = values[j] || '';\n\n // Try to parse as number if it looks like one\n if (value === '') {\n row[header] = null;\n } else if (!Number.isNaN(Number(value)) && value !== '') {\n row[header] = Number(value);\n } else {\n row[header] = value;\n }\n }\n\n data.push(row);\n }\n\n return JSON.stringify({ data }, null, 2);\n }\n\n /**\n * Parses a CSV line handling quoted values\n * @param line - A single line from CSV\n * @returns Array of values\n */\n private parseCsvLine(line: string): string[] {\n const result: string[] = [];\n let current = '';\n let inQuotes = false;\n let skipNext = false;\n\n for (let i = 0; i < line.length; i++) {\n if (skipNext) {\n skipNext = false;\n continue;\n }\n\n const char = line[i];\n\n if (char === '\"') {\n if (inQuotes && line[i + 1] === '\"') {\n // Escaped quote\n current += '\"';\n skipNext = true;\n } else {\n // Toggle quote mode\n inQuotes = !inQuotes;\n }\n } else if (char === ',' && !inQuotes) {\n result.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n\n result.push(current);\n return result;\n }\n\n /**\n * Builds query parameters for cost management report request\n * @param request - The cost management request\n * @returns URLSearchParams with all query parameters\n */\n private buildCostManagementQueryParams(\n request: GetCostManagementRequest,\n ): URLSearchParams {\n const queryParams = new URLSearchParams();\n this.appendBasicQueryParams(queryParams, request);\n this.appendDynamicParams(queryParams, request, 'group_by[');\n this.appendDynamicParams(queryParams, request, 'order_by[');\n this.appendDynamicFilterParams(queryParams, request);\n this.appendDynamicExcludeParams(queryParams, request);\n return queryParams;\n }\n\n /**\n * Appends basic query parameters (currency, delta, and standard filters)\n */\n private appendBasicQueryParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n ): void {\n const basicParams: Array<{\n key: keyof typeof request.query;\n paramName: string;\n needsStringConversion?: boolean;\n }> = [\n { key: 'currency', paramName: 'currency' },\n { key: 'delta', paramName: 'delta' },\n { key: 'category', paramName: 'category' },\n {\n key: 'filter[limit]',\n paramName: 'filter[limit]',\n needsStringConversion: true,\n },\n {\n key: 'filter[offset]',\n paramName: 'filter[offset]',\n needsStringConversion: true,\n },\n { key: 'filter[resolution]', paramName: 'filter[resolution]' },\n {\n key: 'filter[time_scope_units]',\n paramName: 'filter[time_scope_units]',\n },\n {\n key: 'filter[time_scope_value]',\n paramName: 'filter[time_scope_value]',\n needsStringConversion: true,\n },\n {\n key: 'filter[exact:cluster]',\n paramName: 'filter[exact:cluster]',\n },\n ];\n\n for (const { key, paramName, needsStringConversion } of basicParams) {\n const value = request.query[key];\n if (value !== undefined && value !== null && value !== '') {\n queryParams.append(\n paramName,\n needsStringConversion ? String(value) : (value as string),\n );\n }\n }\n }\n\n /**\n * Appends dynamic parameters that match a specific prefix (e.g., 'group_by[', 'order_by[')\n */\n private appendDynamicParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n prefix: string,\n ): void {\n for (const key of Object.keys(request.query)) {\n if (key.startsWith(prefix) && key.endsWith(']')) {\n const value = request.query[key as keyof typeof request.query];\n if (value) {\n queryParams.append(key, String(value));\n }\n }\n }\n }\n\n /**\n * Appends dynamic filter parameters, excluding those already handled explicitly\n */\n private appendDynamicFilterParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n ): void {\n const handledFilterKeys = new Set([\n 'filter[limit]',\n 'filter[offset]',\n 'filter[resolution]',\n 'filter[time_scope_units]',\n 'filter[time_scope_value]',\n ]);\n\n for (const key of Object.keys(request.query)) {\n if (\n key.startsWith('filter[') &&\n key.endsWith(']') &&\n !handledFilterKeys.has(key)\n ) {\n const value = request.query[key as keyof typeof request.query];\n if (value) {\n queryParams.append(key, String(value));\n }\n }\n }\n }\n\n /**\n * Appends dynamic exclude parameters (e.g., exclude[project], exclude[cluster], exclude[tag:key])\n */\n private appendDynamicExcludeParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n ): void {\n for (const key of Object.keys(request.query)) {\n if (key.startsWith('exclude[') && key.endsWith(']')) {\n const value = request.query[key as keyof typeof request.query];\n if (value) {\n queryParams.append(key, String(value));\n }\n }\n }\n }\n\n /**\n * Search OpenShift projects\n * @param search - Search term to filter projects\n * @param options - Optional request options including token and limit\n * @param options.token - Bearer token for authentication (backend use)\n * @param options.limit - Maximum number of results to return (default: 10, use large number for all)\n */\n public async searchOpenShiftProjects(\n search: string = '',\n options?: { token?: string; limit?: number },\n ): Promise<\n TypedResponse<{ data: Array<{ value: string }>; meta?: any; links?: any }>\n > {\n const url = await this.buildResourceTypeUrl(\n 'openshift-projects',\n search,\n options?.limit,\n );\n\n // If token provided externally (backend use), use it directly\n if (options?.token) {\n return await this.fetchWithExternalToken(url, options.token);\n }\n\n // If no external token, use internal token retrieval\n return await this.fetchResourceType(url);\n }\n\n /**\n * Search OpenShift clusters\n * @param search - Search term to filter clusters\n */\n public async searchOpenShiftClusters(\n search: string = '',\n options?: { token?: string; limit?: number },\n ): Promise<\n TypedResponse<{\n data: Array<{ value: string; cluster_alias: string }>;\n meta?: any;\n links?: any;\n }>\n > {\n const url = await this.buildResourceTypeUrl(\n 'openshift-clusters',\n search,\n options?.limit,\n );\n\n // If token provided externally (backend use), use it directly\n if (options?.token) {\n return await this.fetchWithExternalToken(url, options.token);\n }\n\n // If no external token, use internal token retrieval\n return await this.fetchResourceType(url);\n }\n\n /**\n * Search OpenShift nodes\n * @param search - Search term to filter nodes\n */\n public async searchOpenShiftNodes(\n search: string = '',\n ): Promise<\n TypedResponse<{ data: Array<{ value: string }>; meta?: any; links?: any }>\n > {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const searchParam = search ? `?search=${encodeURIComponent(search)}` : '';\n const url = `${baseUrl}/proxy/resource-types/openshift-nodes/${searchParam}`;\n\n return await this.fetchResourceType(url);\n }\n\n /**\n * Get OpenShift tags\n * @param timeScopeValue - Time scope value (-1 for month-to-date, -2 for previous-month). Defaults to -1.\n * @returns TypedResponse with array of tag strings\n */\n public async getOpenShiftTags(\n timeScopeValue: number = -1,\n ): Promise<TypedResponse<{ data: string[]; meta?: any; links?: any }>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const url = `${baseUrl}/proxy/tags/openshift/?filter[time_scope_value]=${timeScopeValue}&key_only=true&limit=1000`;\n\n return await this.fetchViaBackendProxy<{\n data: string[];\n meta?: any;\n links?: any;\n }>(url);\n }\n\n /**\n * Get OpenShift tag values for a specific tag key\n * @param tagKey - The tag key to get values for\n * @param timeScopeValue - Time scope value (-1 for month-to-date, -2 for previous-month). Defaults to -1.\n * @returns TypedResponse with array of tag value objects\n */\n public async getOpenShiftTagValues(\n tagKey: string,\n timeScopeValue: number = -1,\n ): Promise<\n TypedResponse<{\n data: Array<{ key: string; values: string[]; enabled: boolean }>;\n meta?: any;\n links?: any;\n }>\n > {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const url = `${baseUrl}/proxy/tags/openshift/?filter[key]=${encodeURIComponent(\n tagKey,\n )}&filter[time_scope_value]=${timeScopeValue}`;\n\n return await this.fetchViaBackendProxy<{\n data: Array<{ key: string; values: string[]; enabled: boolean }>;\n meta?: any;\n links?: any;\n }>(url);\n }\n\n private async fetchResourceType(url: string): Promise<\n TypedResponse<{\n data: Array<{ value: string; cluster_alias: string }>;\n meta?: any;\n links?: any;\n }>\n > {\n return await this.fetchViaBackendProxy<{\n data: Array<{ value: string; cluster_alias: string }>;\n meta?: any;\n links?: any;\n }>(url);\n }\n\n /**\n * Builds resource type URL routed through the backend secure proxy\n */\n private async buildResourceTypeUrl(\n resourceType: string,\n search?: string,\n limit?: number,\n ): Promise<string> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n\n const params = new URLSearchParams();\n if (search) {\n params.append('search', search);\n }\n if (limit !== undefined) {\n params.append('limit', String(limit));\n }\n const queryString = params.toString();\n const queryPart = queryString ? `?${queryString}` : '';\n\n return `${baseUrl}/proxy/resource-types/${resourceType}/${queryPart}`;\n }\n\n /**\n * Fetches with externally provided token (for backend use).\n * This path bypasses the secure proxy since it's already server-side.\n */\n private async fetchWithExternalToken<T>(\n url: string,\n token: string,\n ): Promise<TypedResponse<T>> {\n const response = await this.fetchApi.fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n method: 'GET',\n });\n\n if (!response.ok) {\n throw new Error(response.statusText);\n }\n\n return {\n ok: response.ok,\n status: response.status,\n json: async () => response.json(),\n } as TypedResponse<T>;\n }\n\n /**\n * Fetches a URL via the backend secure proxy. No Authorization header\n * is sent; the backend injects the SSO token and RBAC filters\n * server-side. Authentication is via the Backstage session cookie.\n */\n private async fetchViaBackendProxy<T>(\n url: string,\n ): Promise<TypedResponse<T>> {\n const response = await this.fetchApi.fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'GET',\n });\n\n if (!response.ok) {\n throw new Error(response.statusText);\n }\n\n return {\n ...response,\n json: async () => {\n const data = (await response.json()) as T;\n return data;\n },\n };\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CostManagementSlimClient.esm.js","sources":["../../../src/clients/cost-management/CostManagementSlimClient.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport crossFetch from 'cross-fetch';\nimport { pluginId } from '../../generated/pluginId';\nimport type { TypedResponse } from '../../generated/apis';\nimport type {\n CostManagementReport,\n GetCostManagementRequest,\n DownloadCostManagementRequest,\n} from './types';\nimport type { CostManagementSlimApi } from './CostManagementSlimApi';\n/**\n * Client for Cost Management data.\n *\n * In the frontend, requests are routed through the backend plugin's secure\n * proxy (`/api/cost-management/proxy/...`), which keeps the SSO token\n * server-side and enforces RBAC before forwarding to the Cost Management API.\n *\n * @public\n */\nexport class CostManagementSlimClient implements CostManagementSlimApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: { discoveryApi: DiscoveryApi; fetchApi?: FetchApi }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi ?? { fetch: crossFetch };\n }\n\n public async getCostManagementReport(\n request: GetCostManagementRequest,\n ): Promise<TypedResponse<CostManagementReport>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const uri = '/proxy/reports/openshift/costs/';\n\n const queryParams = this.buildCostManagementQueryParams(request);\n\n const queryString = queryParams.toString();\n const queryPart = queryString ? `?${queryString}` : '';\n const url = `${baseUrl}${uri}${queryPart}`;\n\n return await this.fetchViaBackendProxy<CostManagementReport>(url);\n }\n\n public async downloadCostManagementReport(\n request: DownloadCostManagementRequest,\n ): Promise<void> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const uri = '/proxy/reports/openshift/costs/';\n\n const downloadRequest: GetCostManagementRequest = {\n query: {\n ...request.query,\n 'filter[limit]': 0,\n },\n };\n delete downloadRequest.query['filter[offset]'];\n\n const queryParams = this.buildCostManagementQueryParams(downloadRequest);\n\n const queryString = queryParams.toString();\n const queryPart = queryString ? `?${queryString}` : '';\n const url = `${baseUrl}${uri}${queryPart}`;\n\n const acceptHeader =\n request.format === 'csv' ? 'text/csv' : 'application/json';\n\n const response = await this.fetchApi.fetch(url, {\n headers: {\n Accept: acceptHeader,\n },\n method: 'GET',\n });\n\n if (!response.ok) {\n let message = response.statusText;\n try {\n const body = (await response.json()) as any;\n if (body.error) message = body.error;\n } catch {\n // response may not be JSON\n }\n throw new Error(message);\n }\n\n // Get the response data\n const responseContentType = response.headers.get('content-type') || '';\n const responseText = await response.text();\n\n let data: string;\n let mimeType: string;\n\n if (request.format === 'csv') {\n // User wants CSV - use response as-is (API returns CSV by default)\n data = responseText;\n mimeType = 'text/csv';\n } else {\n // User wants JSON\n if (responseContentType.includes('application/json')) {\n // Response is already JSON\n const jsonData = JSON.parse(responseText);\n data = JSON.stringify(jsonData, null, 2);\n } else {\n // Response is CSV, need to convert to JSON\n data = this.convertCsvToJson(responseText);\n }\n mimeType = 'application/json';\n }\n\n // Generate filename with timestamp\n const timestamp = new Date().toISOString().replaceAll(/[:.]/g, '-');\n const extension = request.format;\n const filename = `openshift-costs-${timestamp}.${extension}`;\n\n // Trigger download in browser\n const blob = new Blob([data], { type: mimeType });\n const downloadUrl = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = downloadUrl;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n link.remove();\n URL.revokeObjectURL(downloadUrl);\n }\n\n /**\n * Converts CSV string to JSON string\n * @param csv - The CSV data as a string\n * @returns JSON string representation of the CSV data\n */\n private convertCsvToJson(csv: string): string {\n // Normalize line endings (handle both \\r\\n and \\r)\n const normalizedCsv = csv.replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n');\n const lines = normalizedCsv.trim().split('\\n');\n if (lines.length === 0) {\n return JSON.stringify({ data: [] }, null, 2);\n }\n\n const headers = this.parseCsvLine(lines[0]);\n const data: Record<string, string | number | null>[] = [];\n\n for (let i = 1; i < lines.length; i++) {\n const values = this.parseCsvLine(lines[i]);\n const row: Record<string, string | number | null> = {};\n\n for (let j = 0; j < headers.length; j++) {\n const header = headers[j];\n const value = values[j] || '';\n\n // Try to parse as number if it looks like one\n if (value === '') {\n row[header] = null;\n } else if (!Number.isNaN(Number(value)) && value !== '') {\n row[header] = Number(value);\n } else {\n row[header] = value;\n }\n }\n\n data.push(row);\n }\n\n return JSON.stringify({ data }, null, 2);\n }\n\n /**\n * Parses a CSV line handling quoted values\n * @param line - A single line from CSV\n * @returns Array of values\n */\n private parseCsvLine(line: string): string[] {\n const result: string[] = [];\n let current = '';\n let inQuotes = false;\n let skipNext = false;\n\n for (let i = 0; i < line.length; i++) {\n if (skipNext) {\n skipNext = false;\n continue;\n }\n\n const char = line[i];\n\n if (char === '\"') {\n if (inQuotes && line[i + 1] === '\"') {\n // Escaped quote\n current += '\"';\n skipNext = true;\n } else {\n // Toggle quote mode\n inQuotes = !inQuotes;\n }\n } else if (char === ',' && !inQuotes) {\n result.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n\n result.push(current);\n return result;\n }\n\n /**\n * Builds query parameters for cost management report request\n * @param request - The cost management request\n * @returns URLSearchParams with all query parameters\n */\n private buildCostManagementQueryParams(\n request: GetCostManagementRequest,\n ): URLSearchParams {\n const queryParams = new URLSearchParams();\n this.appendBasicQueryParams(queryParams, request);\n this.appendDynamicParams(queryParams, request, 'group_by[');\n this.appendDynamicParams(queryParams, request, 'order_by[');\n this.appendDynamicFilterParams(queryParams, request);\n this.appendDynamicExcludeParams(queryParams, request);\n return queryParams;\n }\n\n /**\n * Appends basic query parameters (currency, delta, and standard filters)\n */\n private appendBasicQueryParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n ): void {\n const basicParams: Array<{\n key: keyof typeof request.query;\n paramName: string;\n needsStringConversion?: boolean;\n }> = [\n { key: 'currency', paramName: 'currency' },\n { key: 'delta', paramName: 'delta' },\n { key: 'category', paramName: 'category' },\n {\n key: 'filter[limit]',\n paramName: 'filter[limit]',\n needsStringConversion: true,\n },\n {\n key: 'filter[offset]',\n paramName: 'filter[offset]',\n needsStringConversion: true,\n },\n { key: 'filter[resolution]', paramName: 'filter[resolution]' },\n {\n key: 'filter[time_scope_units]',\n paramName: 'filter[time_scope_units]',\n },\n {\n key: 'filter[time_scope_value]',\n paramName: 'filter[time_scope_value]',\n needsStringConversion: true,\n },\n {\n key: 'filter[exact:cluster]',\n paramName: 'filter[exact:cluster]',\n },\n ];\n\n for (const { key, paramName, needsStringConversion } of basicParams) {\n const value = request.query[key];\n if (value !== undefined && value !== null && value !== '') {\n queryParams.append(\n paramName,\n needsStringConversion ? String(value) : (value as string),\n );\n }\n }\n }\n\n /**\n * Appends dynamic parameters that match a specific prefix (e.g., 'group_by[', 'order_by[')\n */\n private appendDynamicParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n prefix: string,\n ): void {\n for (const key of Object.keys(request.query)) {\n if (key.startsWith(prefix) && key.endsWith(']')) {\n const value = request.query[key as keyof typeof request.query];\n if (value) {\n queryParams.append(key, String(value));\n }\n }\n }\n }\n\n /**\n * Appends dynamic filter parameters, excluding those already handled explicitly\n */\n private appendDynamicFilterParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n ): void {\n const handledFilterKeys = new Set([\n 'filter[limit]',\n 'filter[offset]',\n 'filter[resolution]',\n 'filter[time_scope_units]',\n 'filter[time_scope_value]',\n ]);\n\n for (const key of Object.keys(request.query)) {\n if (\n key.startsWith('filter[') &&\n key.endsWith(']') &&\n !handledFilterKeys.has(key)\n ) {\n const value = request.query[key as keyof typeof request.query];\n if (value) {\n queryParams.append(key, String(value));\n }\n }\n }\n }\n\n /**\n * Appends dynamic exclude parameters (e.g., exclude[project], exclude[cluster], exclude[tag:key])\n */\n private appendDynamicExcludeParams(\n queryParams: URLSearchParams,\n request: GetCostManagementRequest,\n ): void {\n for (const key of Object.keys(request.query)) {\n if (key.startsWith('exclude[') && key.endsWith(']')) {\n const value = request.query[key as keyof typeof request.query];\n if (value) {\n queryParams.append(key, String(value));\n }\n }\n }\n }\n\n /**\n * Search OpenShift projects\n * @param search - Search term to filter projects\n * @param options - Optional request options including token and limit\n * @param options.token - Bearer token for authentication (backend use)\n * @param options.limit - Maximum number of results to return (default: 10, use large number for all)\n */\n public async searchOpenShiftProjects(\n search: string = '',\n options?: { token?: string; limit?: number },\n ): Promise<\n TypedResponse<{ data: Array<{ value: string }>; meta?: any; links?: any }>\n > {\n const url = await this.buildResourceTypeUrl(\n 'openshift-projects',\n search,\n options?.limit,\n );\n\n // If token provided externally (backend use), use it directly\n if (options?.token) {\n return await this.fetchWithExternalToken(url, options.token);\n }\n\n // If no external token, use internal token retrieval\n return await this.fetchResourceType(url);\n }\n\n /**\n * Search OpenShift clusters\n * @param search - Search term to filter clusters\n */\n public async searchOpenShiftClusters(\n search: string = '',\n options?: { token?: string; limit?: number },\n ): Promise<\n TypedResponse<{\n data: Array<{ value: string; cluster_alias: string }>;\n meta?: any;\n links?: any;\n }>\n > {\n const url = await this.buildResourceTypeUrl(\n 'openshift-clusters',\n search,\n options?.limit,\n );\n\n // If token provided externally (backend use), use it directly\n if (options?.token) {\n return await this.fetchWithExternalToken(url, options.token);\n }\n\n // If no external token, use internal token retrieval\n return await this.fetchResourceType(url);\n }\n\n /**\n * Search OpenShift nodes\n * @param search - Search term to filter nodes\n */\n public async searchOpenShiftNodes(\n search: string = '',\n ): Promise<\n TypedResponse<{ data: Array<{ value: string }>; meta?: any; links?: any }>\n > {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const searchParam = search ? `?search=${encodeURIComponent(search)}` : '';\n const url = `${baseUrl}/proxy/resource-types/openshift-nodes/${searchParam}`;\n\n return await this.fetchResourceType(url);\n }\n\n /**\n * Get OpenShift tags\n * @param timeScopeValue - Time scope value (-1 for month-to-date, -2 for previous-month). Defaults to -1.\n * @returns TypedResponse with array of tag strings\n */\n public async getOpenShiftTags(\n timeScopeValue: number = -1,\n ): Promise<TypedResponse<{ data: string[]; meta?: any; links?: any }>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const url = `${baseUrl}/proxy/tags/openshift/?filter[time_scope_value]=${timeScopeValue}&key_only=true&limit=1000`;\n\n return await this.fetchViaBackendProxy<{\n data: string[];\n meta?: any;\n links?: any;\n }>(url);\n }\n\n /**\n * Get OpenShift tag values for a specific tag key\n * @param tagKey - The tag key to get values for\n * @param timeScopeValue - Time scope value (-1 for month-to-date, -2 for previous-month). Defaults to -1.\n * @returns TypedResponse with array of tag value objects\n */\n public async getOpenShiftTagValues(\n tagKey: string,\n timeScopeValue: number = -1,\n ): Promise<\n TypedResponse<{\n data: Array<{ key: string; values: string[]; enabled: boolean }>;\n meta?: any;\n links?: any;\n }>\n > {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const url = `${baseUrl}/proxy/tags/openshift/?filter[key]=${encodeURIComponent(\n tagKey,\n )}&filter[time_scope_value]=${timeScopeValue}`;\n\n return await this.fetchViaBackendProxy<{\n data: Array<{ key: string; values: string[]; enabled: boolean }>;\n meta?: any;\n links?: any;\n }>(url);\n }\n\n private async fetchResourceType(url: string): Promise<\n TypedResponse<{\n data: Array<{ value: string; cluster_alias: string }>;\n meta?: any;\n links?: any;\n }>\n > {\n return await this.fetchViaBackendProxy<{\n data: Array<{ value: string; cluster_alias: string }>;\n meta?: any;\n links?: any;\n }>(url);\n }\n\n /**\n * Builds resource type URL routed through the backend secure proxy\n */\n private async buildResourceTypeUrl(\n resourceType: string,\n search?: string,\n limit?: number,\n ): Promise<string> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n\n const params = new URLSearchParams();\n if (search) {\n params.append('search', search);\n }\n if (limit !== undefined) {\n params.append('limit', String(limit));\n }\n const queryString = params.toString();\n const queryPart = queryString ? `?${queryString}` : '';\n\n return `${baseUrl}/proxy/resource-types/${resourceType}/${queryPart}`;\n }\n\n /**\n * Fetches with externally provided token (for backend use).\n * This path bypasses the secure proxy since it's already server-side.\n */\n private async fetchWithExternalToken<T>(\n url: string,\n token: string,\n ): Promise<TypedResponse<T>> {\n const response = await this.fetchApi.fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n method: 'GET',\n });\n\n if (!response.ok) {\n let message = response.statusText;\n try {\n const body = (await response.json()) as any;\n if (body.error) message = body.error;\n } catch {\n // response may not be JSON\n }\n throw new Error(message);\n }\n\n return {\n ok: response.ok,\n status: response.status,\n json: async () => response.json(),\n } as TypedResponse<T>;\n }\n\n /**\n * Fetches a URL via the backend secure proxy. No Authorization header\n * is sent; the backend injects the SSO token and RBAC filters\n * server-side. Authentication is via the Backstage session cookie.\n */\n private async fetchViaBackendProxy<T>(\n url: string,\n ): Promise<TypedResponse<T>> {\n const response = await this.fetchApi.fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'GET',\n });\n\n if (!response.ok) {\n let message = response.statusText;\n try {\n const body = (await response.json()) as any;\n if (body.error) message = body.error;\n } catch {\n // response may not be JSON\n }\n throw new Error(message);\n }\n\n return {\n ...response,\n json: async () => {\n const data = (await response.json()) as T;\n return data;\n },\n };\n }\n}\n"],"names":[],"mappings":";;;AAmCO,MAAM,wBAAA,CAA0D;AAAA,EACpD,YAAA;AAAA,EACA,QAAA;AAAA,EAEjB,YAAY,OAAA,EAA8D;AACxE,IAAA,IAAA,CAAK,eAAe,OAAA,CAAQ,YAAA;AAC5B,IAAA,IAAA,CAAK,QAAA,GAAW,OAAA,CAAQ,QAAA,IAAY,EAAE,OAAO,UAAA,EAAW;AAAA,EAC1D;AAAA,EAEA,MAAa,wBACX,OAAA,EAC8C;AAC9C,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,YAAA,CAAa,WAAW,QAAQ,CAAA;AAC3D,IAAA,MAAM,GAAA,GAAM,iCAAA;AAEZ,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,8BAAA,CAA+B,OAAO,CAAA;AAE/D,IAAA,MAAM,WAAA,GAAc,YAAY,QAAA,EAAS;AACzC,IAAA,MAAM,SAAA,GAAY,WAAA,GAAc,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA,GAAK,EAAA;AACpD,IAAA,MAAM,MAAM,CAAA,EAAG,OAAO,CAAA,EAAG,GAAG,GAAG,SAAS,CAAA,CAAA;AAExC,IAAA,OAAO,MAAM,IAAA,CAAK,oBAAA,CAA2C,GAAG,CAAA;AAAA,EAClE;AAAA,EAEA,MAAa,6BACX,OAAA,EACe;AACf,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,YAAA,CAAa,WAAW,QAAQ,CAAA;AAC3D,IAAA,MAAM,GAAA,GAAM,iCAAA;AAEZ,IAAA,MAAM,eAAA,GAA4C;AAAA,MAChD,KAAA,EAAO;AAAA,QACL,GAAG,OAAA,CAAQ,KAAA;AAAA,QACX,eAAA,EAAiB;AAAA;AACnB,KACF;AACA,IAAA,OAAO,eAAA,CAAgB,MAAM,gBAAgB,CAAA;AAE7C,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,8BAAA,CAA+B,eAAe,CAAA;AAEvE,IAAA,MAAM,WAAA,GAAc,YAAY,QAAA,EAAS;AACzC,IAAA,MAAM,SAAA,GAAY,WAAA,GAAc,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA,GAAK,EAAA;AACpD,IAAA,MAAM,MAAM,CAAA,EAAG,OAAO,CAAA,EAAG,GAAG,GAAG,SAAS,CAAA,CAAA;AAExC,IAAA,MAAM,YAAA,GACJ,OAAA,CAAQ,MAAA,KAAW,KAAA,GAAQ,UAAA,GAAa,kBAAA;AAE1C,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,QAAA,CAAS,MAAM,GAAA,EAAK;AAAA,MAC9C,OAAA,EAAS;AAAA,QACP,MAAA,EAAQ;AAAA,OACV;AAAA,MACA,MAAA,EAAQ;AAAA,KACT,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,IAAI,UAAU,QAAA,CAAS,UAAA;AACvB,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,QAAA,IAAI,IAAA,CAAK,KAAA,EAAO,OAAA,GAAU,IAAA,CAAK,KAAA;AAAA,MACjC,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,IACzB;AAGA,IAAA,MAAM,mBAAA,GAAsB,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,IAAK,EAAA;AACpE,IAAA,MAAM,YAAA,GAAe,MAAM,QAAA,CAAS,IAAA,EAAK;AAEzC,IAAA,IAAI,IAAA;AACJ,IAAA,IAAI,QAAA;AAEJ,IAAA,IAAI,OAAA,CAAQ,WAAW,KAAA,EAAO;AAE5B,MAAA,IAAA,GAAO,YAAA;AACP,MAAA,QAAA,GAAW,UAAA;AAAA,IACb,CAAA,MAAO;AAEL,MAAA,IAAI,mBAAA,CAAoB,QAAA,CAAS,kBAAkB,CAAA,EAAG;AAEpD,QAAA,MAAM,QAAA,GAAW,IAAA,CAAK,KAAA,CAAM,YAAY,CAAA;AACxC,QAAA,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,QAAA,EAAU,IAAA,EAAM,CAAC,CAAA;AAAA,MACzC,CAAA,MAAO;AAEL,QAAA,IAAA,GAAO,IAAA,CAAK,iBAAiB,YAAY,CAAA;AAAA,MAC3C;AACA,MAAA,QAAA,GAAW,kBAAA;AAAA,IACb;AAGA,IAAA,MAAM,SAAA,GAAA,qBAAgB,IAAA,EAAK,EAAE,aAAY,CAAE,UAAA,CAAW,SAAS,GAAG,CAAA;AAClE,IAAA,MAAM,YAAY,OAAA,CAAQ,MAAA;AAC1B,IAAA,MAAM,QAAA,GAAW,CAAA,gBAAA,EAAmB,SAAS,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA;AAG1D,IAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,CAAC,IAAI,CAAA,EAAG,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA;AAChD,IAAA,MAAM,WAAA,GAAc,GAAA,CAAI,eAAA,CAAgB,IAAI,CAAA;AAC5C,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,aAAA,CAAc,GAAG,CAAA;AACvC,IAAA,IAAA,CAAK,IAAA,GAAO,WAAA;AACZ,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,QAAA,CAAS,IAAA,CAAK,YAAY,IAAI,CAAA;AAC9B,IAAA,IAAA,CAAK,KAAA,EAAM;AACX,IAAA,IAAA,CAAK,MAAA,EAAO;AACZ,IAAA,GAAA,CAAI,gBAAgB,WAAW,CAAA;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,iBAAiB,GAAA,EAAqB;AAE5C,IAAA,MAAM,aAAA,GAAgB,IAAI,UAAA,CAAW,MAAA,EAAQ,IAAI,CAAA,CAAE,UAAA,CAAW,MAAM,IAAI,CAAA;AACxE,IAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,IAAA,EAAK,CAAE,MAAM,IAAI,CAAA;AAC7C,IAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,MAAA,OAAO,IAAA,CAAK,UAAU,EAAE,IAAA,EAAM,EAAC,EAAE,EAAG,MAAM,CAAC,CAAA;AAAA,IAC7C;AAEA,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,YAAA,CAAa,KAAA,CAAM,CAAC,CAAC,CAAA;AAC1C,IAAA,MAAM,OAAiD,EAAC;AAExD,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,YAAA,CAAa,KAAA,CAAM,CAAC,CAAC,CAAA;AACzC,MAAA,MAAM,MAA8C,EAAC;AAErD,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,CAAQ,QAAQ,CAAA,EAAA,EAAK;AACvC,QAAA,MAAM,MAAA,GAAS,QAAQ,CAAC,CAAA;AACxB,QAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,CAAC,CAAA,IAAK,EAAA;AAG3B,QAAA,IAAI,UAAU,EAAA,EAAI;AAChB,UAAA,GAAA,CAAI,MAAM,CAAA,GAAI,IAAA;AAAA,QAChB,CAAA,MAAA,IAAW,CAAC,MAAA,CAAO,KAAA,CAAM,OAAO,KAAK,CAAC,CAAA,IAAK,KAAA,KAAU,EAAA,EAAI;AACvD,UAAA,GAAA,CAAI,MAAM,CAAA,GAAI,MAAA,CAAO,KAAK,CAAA;AAAA,QAC5B,CAAA,MAAO;AACL,UAAA,GAAA,CAAI,MAAM,CAAA,GAAI,KAAA;AAAA,QAChB;AAAA,MACF;AAEA,MAAA,IAAA,CAAK,KAAK,GAAG,CAAA;AAAA,IACf;AAEA,IAAA,OAAO,KAAK,SAAA,CAAU,EAAE,IAAA,EAAK,EAAG,MAAM,CAAC,CAAA;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,aAAa,IAAA,EAAwB;AAC3C,IAAA,MAAM,SAAmB,EAAC;AAC1B,IAAA,IAAI,OAAA,GAAU,EAAA;AACd,IAAA,IAAI,QAAA,GAAW,KAAA;AACf,IAAA,IAAI,QAAA,GAAW,KAAA;AAEf,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,QAAQ,CAAA,EAAA,EAAK;AACpC,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,QAAA,GAAW,KAAA;AACX,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,GAAO,KAAK,CAAC,CAAA;AAEnB,MAAA,IAAI,SAAS,GAAA,EAAK;AAChB,QAAA,IAAI,QAAA,IAAY,IAAA,CAAK,CAAA,GAAI,CAAC,MAAM,GAAA,EAAK;AAEnC,UAAA,OAAA,IAAW,GAAA;AACX,UAAA,QAAA,GAAW,IAAA;AAAA,QACb,CAAA,MAAO;AAEL,UAAA,QAAA,GAAW,CAAC,QAAA;AAAA,QACd;AAAA,MACF,CAAA,MAAA,IAAW,IAAA,KAAS,GAAA,IAAO,CAAC,QAAA,EAAU;AACpC,QAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,QAAA,OAAA,GAAU,EAAA;AAAA,MACZ,CAAA,MAAO;AACL,QAAA,OAAA,IAAW,IAAA;AAAA,MACb;AAAA,IACF;AAEA,IAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,+BACN,OAAA,EACiB;AACjB,IAAA,MAAM,WAAA,GAAc,IAAI,eAAA,EAAgB;AACxC,IAAA,IAAA,CAAK,sBAAA,CAAuB,aAAa,OAAO,CAAA;AAChD,IAAA,IAAA,CAAK,mBAAA,CAAoB,WAAA,EAAa,OAAA,EAAS,WAAW,CAAA;AAC1D,IAAA,IAAA,CAAK,mBAAA,CAAoB,WAAA,EAAa,OAAA,EAAS,WAAW,CAAA;AAC1D,IAAA,IAAA,CAAK,yBAAA,CAA0B,aAAa,OAAO,CAAA;AACnD,IAAA,IAAA,CAAK,0BAAA,CAA2B,aAAa,OAAO,CAAA;AACpD,IAAA,OAAO,WAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAAA,CACN,aACA,OAAA,EACM;AACN,IAAA,MAAM,WAAA,GAID;AAAA,MACH,EAAE,GAAA,EAAK,UAAA,EAAY,SAAA,EAAW,UAAA,EAAW;AAAA,MACzC,EAAE,GAAA,EAAK,OAAA,EAAS,SAAA,EAAW,OAAA,EAAQ;AAAA,MACnC,EAAE,GAAA,EAAK,UAAA,EAAY,SAAA,EAAW,UAAA,EAAW;AAAA,MACzC;AAAA,QACE,GAAA,EAAK,eAAA;AAAA,QACL,SAAA,EAAW,eAAA;AAAA,QACX,qBAAA,EAAuB;AAAA,OACzB;AAAA,MACA;AAAA,QACE,GAAA,EAAK,gBAAA;AAAA,QACL,SAAA,EAAW,gBAAA;AAAA,QACX,qBAAA,EAAuB;AAAA,OACzB;AAAA,MACA,EAAE,GAAA,EAAK,oBAAA,EAAsB,SAAA,EAAW,oBAAA,EAAqB;AAAA,MAC7D;AAAA,QACE,GAAA,EAAK,0BAAA;AAAA,QACL,SAAA,EAAW;AAAA,OACb;AAAA,MACA;AAAA,QACE,GAAA,EAAK,0BAAA;AAAA,QACL,SAAA,EAAW,0BAAA;AAAA,QACX,qBAAA,EAAuB;AAAA,OACzB;AAAA,MACA;AAAA,QACE,GAAA,EAAK,uBAAA;AAAA,QACL,SAAA,EAAW;AAAA;AACb,KACF;AAEA,IAAA,KAAA,MAAW,EAAE,GAAA,EAAK,SAAA,EAAW,qBAAA,MAA2B,WAAA,EAAa;AACnE,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,GAAG,CAAA;AAC/B,MAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,IAAQ,UAAU,EAAA,EAAI;AACzD,QAAA,WAAA,CAAY,MAAA;AAAA,UACV,SAAA;AAAA,UACA,qBAAA,GAAwB,MAAA,CAAO,KAAK,CAAA,GAAK;AAAA,SAC3C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAA,CACN,WAAA,EACA,OAAA,EACA,MAAA,EACM;AACN,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC5C,MAAA,IAAI,IAAI,UAAA,CAAW,MAAM,KAAK,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,EAAG;AAC/C,QAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,GAAiC,CAAA;AAC7D,QAAA,IAAI,KAAA,EAAO;AACT,UAAA,WAAA,CAAY,MAAA,CAAO,GAAA,EAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,yBAAA,CACN,aACA,OAAA,EACM;AACN,IAAA,MAAM,iBAAA,uBAAwB,GAAA,CAAI;AAAA,MAChC,eAAA;AAAA,MACA,gBAAA;AAAA,MACA,oBAAA;AAAA,MACA,0BAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC5C,MAAA,IACE,GAAA,CAAI,UAAA,CAAW,SAAS,CAAA,IACxB,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,IAChB,CAAC,iBAAA,CAAkB,GAAA,CAAI,GAAG,CAAA,EAC1B;AACA,QAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,GAAiC,CAAA;AAC7D,QAAA,IAAI,KAAA,EAAO;AACT,UAAA,WAAA,CAAY,MAAA,CAAO,GAAA,EAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,0BAAA,CACN,aACA,OAAA,EACM;AACN,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC5C,MAAA,IAAI,IAAI,UAAA,CAAW,UAAU,KAAK,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,EAAG;AACnD,QAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,GAAiC,CAAA;AAC7D,QAAA,IAAI,KAAA,EAAO;AACT,UAAA,WAAA,CAAY,MAAA,CAAO,GAAA,EAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,uBAAA,CACX,MAAA,GAAiB,EAAA,EACjB,OAAA,EAGA;AACA,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,oBAAA;AAAA,MACrB,oBAAA;AAAA,MACA,MAAA;AAAA,MACA,OAAA,EAAS;AAAA,KACX;AAGA,IAAA,IAAI,SAAS,KAAA,EAAO;AAClB,MAAA,OAAO,MAAM,IAAA,CAAK,sBAAA,CAAuB,GAAA,EAAK,QAAQ,KAAK,CAAA;AAAA,IAC7D;AAGA,IAAA,OAAO,MAAM,IAAA,CAAK,iBAAA,CAAkB,GAAG,CAAA;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAa,uBAAA,CACX,MAAA,GAAiB,EAAA,EACjB,OAAA,EAOA;AACA,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,oBAAA;AAAA,MACrB,oBAAA;AAAA,MACA,MAAA;AAAA,MACA,OAAA,EAAS;AAAA,KACX;AAGA,IAAA,IAAI,SAAS,KAAA,EAAO;AAClB,MAAA,OAAO,MAAM,IAAA,CAAK,sBAAA,CAAuB,GAAA,EAAK,QAAQ,KAAK,CAAA;AAAA,IAC7D;AAGA,IAAA,OAAO,MAAM,IAAA,CAAK,iBAAA,CAAkB,GAAG,CAAA;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAa,oBAAA,CACX,MAAA,GAAiB,EAAA,EAGjB;AACA,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,YAAA,CAAa,WAAW,QAAQ,CAAA;AAC3D,IAAA,MAAM,cAAc,MAAA,GAAS,CAAA,QAAA,EAAW,kBAAA,CAAmB,MAAM,CAAC,CAAA,CAAA,GAAK,EAAA;AACvE,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA,sCAAA,EAAyC,WAAW,CAAA,CAAA;AAE1E,IAAA,OAAO,MAAM,IAAA,CAAK,iBAAA,CAAkB,GAAG,CAAA;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAa,gBAAA,CACX,cAAA,GAAyB,EAAA,EAC4C;AACrE,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,YAAA,CAAa,WAAW,QAAQ,CAAA;AAC3D,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA,gDAAA,EAAmD,cAAc,CAAA,yBAAA,CAAA;AAEvF,IAAA,OAAO,MAAM,IAAA,CAAK,oBAAA,CAIf,GAAG,CAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAa,qBAAA,CACX,MAAA,EACA,cAAA,GAAyB,EAAA,EAOzB;AACA,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,YAAA,CAAa,WAAW,QAAQ,CAAA;AAC3D,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA,mCAAA,EAAsC,kBAAA;AAAA,MAC1D;AAAA,KACD,6BAA6B,cAAc,CAAA,CAAA;AAE5C,IAAA,OAAO,MAAM,IAAA,CAAK,oBAAA,CAIf,GAAG,CAAA;AAAA,EACR;AAAA,EAEA,MAAc,kBAAkB,GAAA,EAM9B;AACA,IAAA,OAAO,MAAM,IAAA,CAAK,oBAAA,CAIf,GAAG,CAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,oBAAA,CACZ,YAAA,EACA,MAAA,EACA,KAAA,EACiB;AACjB,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,YAAA,CAAa,WAAW,QAAQ,CAAA;AAE3D,IAAA,MAAM,MAAA,GAAS,IAAI,eAAA,EAAgB;AACnC,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAA,CAAO,MAAA,CAAO,UAAU,MAAM,CAAA;AAAA,IAChC;AACA,IAAA,IAAI,UAAU,MAAA,EAAW;AACvB,MAAA,MAAA,CAAO,MAAA,CAAO,OAAA,EAAS,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,IACtC;AACA,IAAA,MAAM,WAAA,GAAc,OAAO,QAAA,EAAS;AACpC,IAAA,MAAM,SAAA,GAAY,WAAA,GAAc,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA,GAAK,EAAA;AAEpD,IAAA,OAAO,CAAA,EAAG,OAAO,CAAA,sBAAA,EAAyB,YAAY,IAAI,SAAS,CAAA,CAAA;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,sBAAA,CACZ,GAAA,EACA,KAAA,EAC2B;AAC3B,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,QAAA,CAAS,MAAM,GAAA,EAAK;AAAA,MAC9C,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,aAAA,EAAe,UAAU,KAAK,CAAA;AAAA,OAChC;AAAA,MACA,MAAA,EAAQ;AAAA,KACT,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,IAAI,UAAU,QAAA,CAAS,UAAA;AACvB,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,QAAA,IAAI,IAAA,CAAK,KAAA,EAAO,OAAA,GAAU,IAAA,CAAK,KAAA;AAAA,MACjC,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,IACzB;AAEA,IAAA,OAAO;AAAA,MACL,IAAI,QAAA,CAAS,EAAA;AAAA,MACb,QAAQ,QAAA,CAAS,MAAA;AAAA,MACjB,IAAA,EAAM,YAAY,QAAA,CAAS,IAAA;AAAK,KAClC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,qBACZ,GAAA,EAC2B;AAC3B,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,QAAA,CAAS,MAAM,GAAA,EAAK;AAAA,MAC9C,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB;AAAA,OAClB;AAAA,MACA,MAAA,EAAQ;AAAA,KACT,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,IAAI,UAAU,QAAA,CAAS,UAAA;AACvB,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,QAAA,IAAI,IAAA,CAAK,KAAA,EAAO,OAAA,GAAU,IAAA,CAAK,KAAA;AAAA,MACjC,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,IACzB;AAEA,IAAA,OAAO;AAAA,MACL,GAAG,QAAA;AAAA,MACH,MAAM,YAAY;AAChB,QAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,KACF;AAAA,EACF;AACF;;;;"}
@@ -54,7 +54,13 @@ class OptimizationsClient {
54
54
  snakeCaseTransformedRequest
55
55
  );
56
56
  if (!response.ok) {
57
- throw new Error(response.statusText);
57
+ let message = response.statusText;
58
+ try {
59
+ const body = await response.json();
60
+ if (body.error) message = body.error;
61
+ } catch {
62
+ }
63
+ throw new Error(message);
58
64
  }
59
65
  return {
60
66
  ...response,
@@ -79,7 +85,13 @@ class OptimizationsClient {
79
85
  options
80
86
  );
81
87
  if (!response.ok) {
82
- throw new Error(response.statusText);
88
+ let message = response.statusText;
89
+ try {
90
+ const body = await response.json();
91
+ if (body.error) message = body.error;
92
+ } catch {
93
+ }
94
+ throw new Error(message);
83
95
  }
84
96
  return {
85
97
  ...response,
@@ -1 +1 @@
1
- {"version":3,"file":"OptimizationsClient.cjs.js","sources":["../../../src/clients/optimizations/OptimizationsClient.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport { deepMapKeys } from '../../util/mod';\nimport camelCase from 'lodash/camelCase';\nimport snakeCase from 'lodash/snakeCase';\nimport { pluginId } from '../../generated/pluginId';\nimport {\n DefaultApiClient,\n type RequestOptions,\n type TypedResponse,\n} from '../../generated/apis';\nimport type {\n RecommendationBoxPlots,\n RecommendationList,\n} from '../../generated/models';\nimport type {\n GetRecommendationByIdRequest,\n GetRecommendationListRequest,\n OptimizationsApi,\n} from './types';\n\n/**\n * Client for the Optimizations (ROS) API.\n *\n * In the frontend, requests are routed through the backend plugin's secure\n * proxy (`/api/cost-management/proxy/...`), which keeps the SSO token\n * server-side and enforces RBAC before forwarding to the Cost Management API.\n *\n * When a `token` is provided via `RequestOptions` (backend use-case), the\n * request goes directly to the upstream API.\n *\n * @public\n */\nexport class OptimizationsClient implements OptimizationsApi {\n private static requestKeysToSkip = {\n getRecommendationById: [/path\\.recommendationId$/],\n };\n private static responseKeysToSkip = {\n getRecommendationById: [\n /recommendations\\.recommendation_terms\\.(long|medium|short)_term\\.plots\\.plots_data\\['\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z'\\]$/,\n ],\n };\n\n /** Used for backend-to-RHCC calls (token provided by caller). */\n private readonly directClient: DefaultApiClient;\n /** Used for frontend calls routed through the backend secure proxy. */\n private readonly proxyClient: DefaultApiClient;\n\n constructor(options: { discoveryApi: DiscoveryApi; fetchApi?: FetchApi }) {\n const outerDiscovery = options.discoveryApi;\n\n this.directClient = new DefaultApiClient({\n fetchApi: options.fetchApi,\n discoveryApi: {\n async getBaseUrl() {\n const baseUrl = await outerDiscovery.getBaseUrl('proxy');\n return `${baseUrl}/cost-management/v1`;\n },\n },\n });\n\n this.proxyClient = new DefaultApiClient({\n fetchApi: options.fetchApi,\n discoveryApi: {\n async getBaseUrl() {\n const baseUrl = await outerDiscovery.getBaseUrl(pluginId);\n return `${baseUrl}/proxy`;\n },\n },\n });\n }\n\n public async getRecommendationById(\n request: GetRecommendationByIdRequest,\n ): Promise<TypedResponse<RecommendationBoxPlots>> {\n const snakeCaseTransformedRequest = deepMapKeys(request, {\n onVisitJsonObjectKey: snakeCase as (value: string | number) => string,\n skipList: OptimizationsClient.requestKeysToSkip.getRecommendationById,\n }) as GetRecommendationByIdRequest;\n\n const response = await this.proxyClient.getRecommendationById(\n snakeCaseTransformedRequest,\n );\n\n if (!response.ok) {\n throw new Error(response.statusText);\n }\n\n return {\n ...response,\n json: async () => {\n const data = await response.json();\n const camelCaseTransformedResponse = deepMapKeys(data, {\n onVisitJsonObjectKey: camelCase as (value: string | number) => string,\n skipList:\n OptimizationsClient.responseKeysToSkip.getRecommendationById,\n }) as RecommendationBoxPlots;\n return camelCaseTransformedResponse;\n },\n };\n }\n\n public async getRecommendationList(\n request: GetRecommendationListRequest,\n options?: RequestOptions,\n ): Promise<TypedResponse<RecommendationList>> {\n const snakeCaseTransformedRequest = deepMapKeys(\n request,\n snakeCase as (value: string | number) => string,\n ) as GetRecommendationListRequest;\n\n // Backend use-case: token provided, call RHCC directly\n const client = options?.token ? this.directClient : this.proxyClient;\n\n const response = await client.getRecommendationList(\n snakeCaseTransformedRequest,\n options,\n );\n\n if (!response.ok) {\n throw new Error(response.statusText);\n }\n\n return {\n ...response,\n json: async () => {\n const data = await response.json();\n const camelCaseTransformedResponse = deepMapKeys(\n data,\n camelCase as (value: string | number) => string,\n ) as RecommendationList;\n return camelCaseTransformedResponse;\n },\n };\n }\n}\n"],"names":["DefaultApiClient","pluginId","deepMapKeys","snakeCase","camelCase"],"mappings":";;;;;;;;;;;;;AAgDO,MAAM,mBAAgD,CAAA;AAAA,EAC3D,OAAe,iBAAoB,GAAA;AAAA,IACjC,qBAAA,EAAuB,CAAC,yBAAyB;AAAA,GACnD;AAAA,EACA,OAAe,kBAAqB,GAAA;AAAA,IAClC,qBAAuB,EAAA;AAAA,MACrB;AAAA;AACF,GACF;AAAA;AAAA,EAGiB,YAAA;AAAA;AAAA,EAEA,WAAA;AAAA,EAEjB,YAAY,OAA8D,EAAA;AACxE,IAAA,MAAM,iBAAiB,OAAQ,CAAA,YAAA;AAE/B,IAAK,IAAA,CAAA,YAAA,GAAe,IAAIA,kCAAiB,CAAA;AAAA,MACvC,UAAU,OAAQ,CAAA,QAAA;AAAA,MAClB,YAAc,EAAA;AAAA,QACZ,MAAM,UAAa,GAAA;AACjB,UAAA,MAAM,OAAU,GAAA,MAAM,cAAe,CAAA,UAAA,CAAW,OAAO,CAAA;AACvD,UAAA,OAAO,GAAG,OAAO,CAAA,mBAAA,CAAA;AAAA;AACnB;AACF,KACD,CAAA;AAED,IAAK,IAAA,CAAA,WAAA,GAAc,IAAIA,kCAAiB,CAAA;AAAA,MACtC,UAAU,OAAQ,CAAA,QAAA;AAAA,MAClB,YAAc,EAAA;AAAA,QACZ,MAAM,UAAa,GAAA;AACjB,UAAA,MAAM,OAAU,GAAA,MAAM,cAAe,CAAA,UAAA,CAAWC,iBAAQ,CAAA;AACxD,UAAA,OAAO,GAAG,OAAO,CAAA,MAAA,CAAA;AAAA;AACnB;AACF,KACD,CAAA;AAAA;AACH,EAEA,MAAa,sBACX,OACgD,EAAA;AAChD,IAAM,MAAA,2BAAA,GAA8BC,sBAAY,OAAS,EAAA;AAAA,MACvD,oBAAsB,EAAAC,0BAAA;AAAA,MACtB,QAAA,EAAU,oBAAoB,iBAAkB,CAAA;AAAA,KACjD,CAAA;AAED,IAAM,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,WAAY,CAAA,qBAAA;AAAA,MACtC;AAAA,KACF;AAEA,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,IAAI,KAAM,CAAA,QAAA,CAAS,UAAU,CAAA;AAAA;AAGrC,IAAO,OAAA;AAAA,MACL,GAAG,QAAA;AAAA,MACH,MAAM,YAAY;AAChB,QAAM,MAAA,IAAA,GAAO,MAAM,QAAA,CAAS,IAAK,EAAA;AACjC,QAAM,MAAA,4BAAA,GAA+BD,sBAAY,IAAM,EAAA;AAAA,UACrD,oBAAsB,EAAAE,0BAAA;AAAA,UACtB,QAAA,EACE,oBAAoB,kBAAmB,CAAA;AAAA,SAC1C,CAAA;AACD,QAAO,OAAA,4BAAA;AAAA;AACT,KACF;AAAA;AACF,EAEA,MAAa,qBACX,CAAA,OAAA,EACA,OAC4C,EAAA;AAC5C,IAAA,MAAM,2BAA8B,GAAAF,qBAAA;AAAA,MAClC,OAAA;AAAA,MACAC;AAAA,KACF;AAGA,IAAA,MAAM,MAAS,GAAA,OAAA,EAAS,KAAQ,GAAA,IAAA,CAAK,eAAe,IAAK,CAAA,WAAA;AAEzD,IAAM,MAAA,QAAA,GAAW,MAAM,MAAO,CAAA,qBAAA;AAAA,MAC5B,2BAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,IAAI,KAAM,CAAA,QAAA,CAAS,UAAU,CAAA;AAAA;AAGrC,IAAO,OAAA;AAAA,MACL,GAAG,QAAA;AAAA,MACH,MAAM,YAAY;AAChB,QAAM,MAAA,IAAA,GAAO,MAAM,QAAA,CAAS,IAAK,EAAA;AACjC,QAAA,MAAM,4BAA+B,GAAAD,qBAAA;AAAA,UACnC,IAAA;AAAA,UACAE;AAAA,SACF;AACA,QAAO,OAAA,4BAAA;AAAA;AACT,KACF;AAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"OptimizationsClient.cjs.js","sources":["../../../src/clients/optimizations/OptimizationsClient.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport { deepMapKeys } from '../../util/mod';\nimport camelCase from 'lodash/camelCase';\nimport snakeCase from 'lodash/snakeCase';\nimport { pluginId } from '../../generated/pluginId';\nimport {\n DefaultApiClient,\n type RequestOptions,\n type TypedResponse,\n} from '../../generated/apis';\nimport type {\n RecommendationBoxPlots,\n RecommendationList,\n} from '../../generated/models';\nimport type {\n GetRecommendationByIdRequest,\n GetRecommendationListRequest,\n OptimizationsApi,\n} from './types';\n\n/**\n * Client for the Optimizations (ROS) API.\n *\n * In the frontend, requests are routed through the backend plugin's secure\n * proxy (`/api/cost-management/proxy/...`), which keeps the SSO token\n * server-side and enforces RBAC before forwarding to the Cost Management API.\n *\n * When a `token` is provided via `RequestOptions` (backend use-case), the\n * request goes directly to the upstream API.\n *\n * @public\n */\nexport class OptimizationsClient implements OptimizationsApi {\n private static requestKeysToSkip = {\n getRecommendationById: [/path\\.recommendationId$/],\n };\n private static responseKeysToSkip = {\n getRecommendationById: [\n /recommendations\\.recommendation_terms\\.(long|medium|short)_term\\.plots\\.plots_data\\['\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z'\\]$/,\n ],\n };\n\n /** Used for backend-to-RHCC calls (token provided by caller). */\n private readonly directClient: DefaultApiClient;\n /** Used for frontend calls routed through the backend secure proxy. */\n private readonly proxyClient: DefaultApiClient;\n\n constructor(options: { discoveryApi: DiscoveryApi; fetchApi?: FetchApi }) {\n const outerDiscovery = options.discoveryApi;\n\n this.directClient = new DefaultApiClient({\n fetchApi: options.fetchApi,\n discoveryApi: {\n async getBaseUrl() {\n const baseUrl = await outerDiscovery.getBaseUrl('proxy');\n return `${baseUrl}/cost-management/v1`;\n },\n },\n });\n\n this.proxyClient = new DefaultApiClient({\n fetchApi: options.fetchApi,\n discoveryApi: {\n async getBaseUrl() {\n const baseUrl = await outerDiscovery.getBaseUrl(pluginId);\n return `${baseUrl}/proxy`;\n },\n },\n });\n }\n\n public async getRecommendationById(\n request: GetRecommendationByIdRequest,\n ): Promise<TypedResponse<RecommendationBoxPlots>> {\n const snakeCaseTransformedRequest = deepMapKeys(request, {\n onVisitJsonObjectKey: snakeCase as (value: string | number) => string,\n skipList: OptimizationsClient.requestKeysToSkip.getRecommendationById,\n }) as GetRecommendationByIdRequest;\n\n const response = await this.proxyClient.getRecommendationById(\n snakeCaseTransformedRequest,\n );\n\n if (!response.ok) {\n let message = response.statusText;\n try {\n const body = (await response.json()) as any;\n if (body.error) message = body.error;\n } catch {\n // response may not be JSON\n }\n throw new Error(message);\n }\n\n return {\n ...response,\n json: async () => {\n const data = await response.json();\n const camelCaseTransformedResponse = deepMapKeys(data, {\n onVisitJsonObjectKey: camelCase as (value: string | number) => string,\n skipList:\n OptimizationsClient.responseKeysToSkip.getRecommendationById,\n }) as RecommendationBoxPlots;\n return camelCaseTransformedResponse;\n },\n };\n }\n\n public async getRecommendationList(\n request: GetRecommendationListRequest,\n options?: RequestOptions,\n ): Promise<TypedResponse<RecommendationList>> {\n const snakeCaseTransformedRequest = deepMapKeys(\n request,\n snakeCase as (value: string | number) => string,\n ) as GetRecommendationListRequest;\n\n // Backend use-case: token provided, call RHCC directly\n const client = options?.token ? this.directClient : this.proxyClient;\n\n const response = await client.getRecommendationList(\n snakeCaseTransformedRequest,\n options,\n );\n\n if (!response.ok) {\n let message = response.statusText;\n try {\n const body = (await response.json()) as any;\n if (body.error) message = body.error;\n } catch {\n // response may not be JSON\n }\n throw new Error(message);\n }\n\n return {\n ...response,\n json: async () => {\n const data = await response.json();\n const camelCaseTransformedResponse = deepMapKeys(\n data,\n camelCase as (value: string | number) => string,\n ) as RecommendationList;\n return camelCaseTransformedResponse;\n },\n };\n }\n}\n"],"names":["DefaultApiClient","pluginId","deepMapKeys","snakeCase","camelCase"],"mappings":"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"}
@@ -47,7 +47,13 @@ class OptimizationsClient {
47
47
  snakeCaseTransformedRequest
48
48
  );
49
49
  if (!response.ok) {
50
- throw new Error(response.statusText);
50
+ let message = response.statusText;
51
+ try {
52
+ const body = await response.json();
53
+ if (body.error) message = body.error;
54
+ } catch {
55
+ }
56
+ throw new Error(message);
51
57
  }
52
58
  return {
53
59
  ...response,
@@ -72,7 +78,13 @@ class OptimizationsClient {
72
78
  options
73
79
  );
74
80
  if (!response.ok) {
75
- throw new Error(response.statusText);
81
+ let message = response.statusText;
82
+ try {
83
+ const body = await response.json();
84
+ if (body.error) message = body.error;
85
+ } catch {
86
+ }
87
+ throw new Error(message);
76
88
  }
77
89
  return {
78
90
  ...response,
@@ -1 +1 @@
1
- {"version":3,"file":"OptimizationsClient.esm.js","sources":["../../../src/clients/optimizations/OptimizationsClient.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport { deepMapKeys } from '../../util/mod';\nimport camelCase from 'lodash/camelCase';\nimport snakeCase from 'lodash/snakeCase';\nimport { pluginId } from '../../generated/pluginId';\nimport {\n DefaultApiClient,\n type RequestOptions,\n type TypedResponse,\n} from '../../generated/apis';\nimport type {\n RecommendationBoxPlots,\n RecommendationList,\n} from '../../generated/models';\nimport type {\n GetRecommendationByIdRequest,\n GetRecommendationListRequest,\n OptimizationsApi,\n} from './types';\n\n/**\n * Client for the Optimizations (ROS) API.\n *\n * In the frontend, requests are routed through the backend plugin's secure\n * proxy (`/api/cost-management/proxy/...`), which keeps the SSO token\n * server-side and enforces RBAC before forwarding to the Cost Management API.\n *\n * When a `token` is provided via `RequestOptions` (backend use-case), the\n * request goes directly to the upstream API.\n *\n * @public\n */\nexport class OptimizationsClient implements OptimizationsApi {\n private static requestKeysToSkip = {\n getRecommendationById: [/path\\.recommendationId$/],\n };\n private static responseKeysToSkip = {\n getRecommendationById: [\n /recommendations\\.recommendation_terms\\.(long|medium|short)_term\\.plots\\.plots_data\\['\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z'\\]$/,\n ],\n };\n\n /** Used for backend-to-RHCC calls (token provided by caller). */\n private readonly directClient: DefaultApiClient;\n /** Used for frontend calls routed through the backend secure proxy. */\n private readonly proxyClient: DefaultApiClient;\n\n constructor(options: { discoveryApi: DiscoveryApi; fetchApi?: FetchApi }) {\n const outerDiscovery = options.discoveryApi;\n\n this.directClient = new DefaultApiClient({\n fetchApi: options.fetchApi,\n discoveryApi: {\n async getBaseUrl() {\n const baseUrl = await outerDiscovery.getBaseUrl('proxy');\n return `${baseUrl}/cost-management/v1`;\n },\n },\n });\n\n this.proxyClient = new DefaultApiClient({\n fetchApi: options.fetchApi,\n discoveryApi: {\n async getBaseUrl() {\n const baseUrl = await outerDiscovery.getBaseUrl(pluginId);\n return `${baseUrl}/proxy`;\n },\n },\n });\n }\n\n public async getRecommendationById(\n request: GetRecommendationByIdRequest,\n ): Promise<TypedResponse<RecommendationBoxPlots>> {\n const snakeCaseTransformedRequest = deepMapKeys(request, {\n onVisitJsonObjectKey: snakeCase as (value: string | number) => string,\n skipList: OptimizationsClient.requestKeysToSkip.getRecommendationById,\n }) as GetRecommendationByIdRequest;\n\n const response = await this.proxyClient.getRecommendationById(\n snakeCaseTransformedRequest,\n );\n\n if (!response.ok) {\n throw new Error(response.statusText);\n }\n\n return {\n ...response,\n json: async () => {\n const data = await response.json();\n const camelCaseTransformedResponse = deepMapKeys(data, {\n onVisitJsonObjectKey: camelCase as (value: string | number) => string,\n skipList:\n OptimizationsClient.responseKeysToSkip.getRecommendationById,\n }) as RecommendationBoxPlots;\n return camelCaseTransformedResponse;\n },\n };\n }\n\n public async getRecommendationList(\n request: GetRecommendationListRequest,\n options?: RequestOptions,\n ): Promise<TypedResponse<RecommendationList>> {\n const snakeCaseTransformedRequest = deepMapKeys(\n request,\n snakeCase as (value: string | number) => string,\n ) as GetRecommendationListRequest;\n\n // Backend use-case: token provided, call RHCC directly\n const client = options?.token ? this.directClient : this.proxyClient;\n\n const response = await client.getRecommendationList(\n snakeCaseTransformedRequest,\n options,\n );\n\n if (!response.ok) {\n throw new Error(response.statusText);\n }\n\n return {\n ...response,\n json: async () => {\n const data = await response.json();\n const camelCaseTransformedResponse = deepMapKeys(\n data,\n camelCase as (value: string | number) => string,\n ) as RecommendationList;\n return camelCaseTransformedResponse;\n },\n };\n }\n}\n"],"names":[],"mappings":";;;;;;AAgDO,MAAM,mBAAgD,CAAA;AAAA,EAC3D,OAAe,iBAAoB,GAAA;AAAA,IACjC,qBAAA,EAAuB,CAAC,yBAAyB;AAAA,GACnD;AAAA,EACA,OAAe,kBAAqB,GAAA;AAAA,IAClC,qBAAuB,EAAA;AAAA,MACrB;AAAA;AACF,GACF;AAAA;AAAA,EAGiB,YAAA;AAAA;AAAA,EAEA,WAAA;AAAA,EAEjB,YAAY,OAA8D,EAAA;AACxE,IAAA,MAAM,iBAAiB,OAAQ,CAAA,YAAA;AAE/B,IAAK,IAAA,CAAA,YAAA,GAAe,IAAI,gBAAiB,CAAA;AAAA,MACvC,UAAU,OAAQ,CAAA,QAAA;AAAA,MAClB,YAAc,EAAA;AAAA,QACZ,MAAM,UAAa,GAAA;AACjB,UAAA,MAAM,OAAU,GAAA,MAAM,cAAe,CAAA,UAAA,CAAW,OAAO,CAAA;AACvD,UAAA,OAAO,GAAG,OAAO,CAAA,mBAAA,CAAA;AAAA;AACnB;AACF,KACD,CAAA;AAED,IAAK,IAAA,CAAA,WAAA,GAAc,IAAI,gBAAiB,CAAA;AAAA,MACtC,UAAU,OAAQ,CAAA,QAAA;AAAA,MAClB,YAAc,EAAA;AAAA,QACZ,MAAM,UAAa,GAAA;AACjB,UAAA,MAAM,OAAU,GAAA,MAAM,cAAe,CAAA,UAAA,CAAW,QAAQ,CAAA;AACxD,UAAA,OAAO,GAAG,OAAO,CAAA,MAAA,CAAA;AAAA;AACnB;AACF,KACD,CAAA;AAAA;AACH,EAEA,MAAa,sBACX,OACgD,EAAA;AAChD,IAAM,MAAA,2BAAA,GAA8B,YAAY,OAAS,EAAA;AAAA,MACvD,oBAAsB,EAAA,SAAA;AAAA,MACtB,QAAA,EAAU,oBAAoB,iBAAkB,CAAA;AAAA,KACjD,CAAA;AAED,IAAM,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,WAAY,CAAA,qBAAA;AAAA,MACtC;AAAA,KACF;AAEA,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,IAAI,KAAM,CAAA,QAAA,CAAS,UAAU,CAAA;AAAA;AAGrC,IAAO,OAAA;AAAA,MACL,GAAG,QAAA;AAAA,MACH,MAAM,YAAY;AAChB,QAAM,MAAA,IAAA,GAAO,MAAM,QAAA,CAAS,IAAK,EAAA;AACjC,QAAM,MAAA,4BAAA,GAA+B,YAAY,IAAM,EAAA;AAAA,UACrD,oBAAsB,EAAA,SAAA;AAAA,UACtB,QAAA,EACE,oBAAoB,kBAAmB,CAAA;AAAA,SAC1C,CAAA;AACD,QAAO,OAAA,4BAAA;AAAA;AACT,KACF;AAAA;AACF,EAEA,MAAa,qBACX,CAAA,OAAA,EACA,OAC4C,EAAA;AAC5C,IAAA,MAAM,2BAA8B,GAAA,WAAA;AAAA,MAClC,OAAA;AAAA,MACA;AAAA,KACF;AAGA,IAAA,MAAM,MAAS,GAAA,OAAA,EAAS,KAAQ,GAAA,IAAA,CAAK,eAAe,IAAK,CAAA,WAAA;AAEzD,IAAM,MAAA,QAAA,GAAW,MAAM,MAAO,CAAA,qBAAA;AAAA,MAC5B,2BAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,IAAI,KAAM,CAAA,QAAA,CAAS,UAAU,CAAA;AAAA;AAGrC,IAAO,OAAA;AAAA,MACL,GAAG,QAAA;AAAA,MACH,MAAM,YAAY;AAChB,QAAM,MAAA,IAAA,GAAO,MAAM,QAAA,CAAS,IAAK,EAAA;AACjC,QAAA,MAAM,4BAA+B,GAAA,WAAA;AAAA,UACnC,IAAA;AAAA,UACA;AAAA,SACF;AACA,QAAO,OAAA,4BAAA;AAAA;AACT,KACF;AAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"OptimizationsClient.esm.js","sources":["../../../src/clients/optimizations/OptimizationsClient.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport { deepMapKeys } from '../../util/mod';\nimport camelCase from 'lodash/camelCase';\nimport snakeCase from 'lodash/snakeCase';\nimport { pluginId } from '../../generated/pluginId';\nimport {\n DefaultApiClient,\n type RequestOptions,\n type TypedResponse,\n} from '../../generated/apis';\nimport type {\n RecommendationBoxPlots,\n RecommendationList,\n} from '../../generated/models';\nimport type {\n GetRecommendationByIdRequest,\n GetRecommendationListRequest,\n OptimizationsApi,\n} from './types';\n\n/**\n * Client for the Optimizations (ROS) API.\n *\n * In the frontend, requests are routed through the backend plugin's secure\n * proxy (`/api/cost-management/proxy/...`), which keeps the SSO token\n * server-side and enforces RBAC before forwarding to the Cost Management API.\n *\n * When a `token` is provided via `RequestOptions` (backend use-case), the\n * request goes directly to the upstream API.\n *\n * @public\n */\nexport class OptimizationsClient implements OptimizationsApi {\n private static requestKeysToSkip = {\n getRecommendationById: [/path\\.recommendationId$/],\n };\n private static responseKeysToSkip = {\n getRecommendationById: [\n /recommendations\\.recommendation_terms\\.(long|medium|short)_term\\.plots\\.plots_data\\['\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z'\\]$/,\n ],\n };\n\n /** Used for backend-to-RHCC calls (token provided by caller). */\n private readonly directClient: DefaultApiClient;\n /** Used for frontend calls routed through the backend secure proxy. */\n private readonly proxyClient: DefaultApiClient;\n\n constructor(options: { discoveryApi: DiscoveryApi; fetchApi?: FetchApi }) {\n const outerDiscovery = options.discoveryApi;\n\n this.directClient = new DefaultApiClient({\n fetchApi: options.fetchApi,\n discoveryApi: {\n async getBaseUrl() {\n const baseUrl = await outerDiscovery.getBaseUrl('proxy');\n return `${baseUrl}/cost-management/v1`;\n },\n },\n });\n\n this.proxyClient = new DefaultApiClient({\n fetchApi: options.fetchApi,\n discoveryApi: {\n async getBaseUrl() {\n const baseUrl = await outerDiscovery.getBaseUrl(pluginId);\n return `${baseUrl}/proxy`;\n },\n },\n });\n }\n\n public async getRecommendationById(\n request: GetRecommendationByIdRequest,\n ): Promise<TypedResponse<RecommendationBoxPlots>> {\n const snakeCaseTransformedRequest = deepMapKeys(request, {\n onVisitJsonObjectKey: snakeCase as (value: string | number) => string,\n skipList: OptimizationsClient.requestKeysToSkip.getRecommendationById,\n }) as GetRecommendationByIdRequest;\n\n const response = await this.proxyClient.getRecommendationById(\n snakeCaseTransformedRequest,\n );\n\n if (!response.ok) {\n let message = response.statusText;\n try {\n const body = (await response.json()) as any;\n if (body.error) message = body.error;\n } catch {\n // response may not be JSON\n }\n throw new Error(message);\n }\n\n return {\n ...response,\n json: async () => {\n const data = await response.json();\n const camelCaseTransformedResponse = deepMapKeys(data, {\n onVisitJsonObjectKey: camelCase as (value: string | number) => string,\n skipList:\n OptimizationsClient.responseKeysToSkip.getRecommendationById,\n }) as RecommendationBoxPlots;\n return camelCaseTransformedResponse;\n },\n };\n }\n\n public async getRecommendationList(\n request: GetRecommendationListRequest,\n options?: RequestOptions,\n ): Promise<TypedResponse<RecommendationList>> {\n const snakeCaseTransformedRequest = deepMapKeys(\n request,\n snakeCase as (value: string | number) => string,\n ) as GetRecommendationListRequest;\n\n // Backend use-case: token provided, call RHCC directly\n const client = options?.token ? this.directClient : this.proxyClient;\n\n const response = await client.getRecommendationList(\n snakeCaseTransformedRequest,\n options,\n );\n\n if (!response.ok) {\n let message = response.statusText;\n try {\n const body = (await response.json()) as any;\n if (body.error) message = body.error;\n } catch {\n // response may not be JSON\n }\n throw new Error(message);\n }\n\n return {\n ...response,\n json: async () => {\n const data = await response.json();\n const camelCaseTransformedResponse = deepMapKeys(\n data,\n camelCase as (value: string | number) => string,\n ) as RecommendationList;\n return camelCaseTransformedResponse;\n },\n };\n }\n}\n"],"names":[],"mappings":";;;;;;AAgDO,MAAM,mBAAA,CAAgD;AAAA,EAC3D,OAAe,iBAAA,GAAoB;AAAA,IACjC,qBAAA,EAAuB,CAAC,yBAAyB;AAAA,GACnD;AAAA,EACA,OAAe,kBAAA,GAAqB;AAAA,IAClC,qBAAA,EAAuB;AAAA,MACrB;AAAA;AACF,GACF;AAAA;AAAA,EAGiB,YAAA;AAAA;AAAA,EAEA,WAAA;AAAA,EAEjB,YAAY,OAAA,EAA8D;AACxE,IAAA,MAAM,iBAAiB,OAAA,CAAQ,YAAA;AAE/B,IAAA,IAAA,CAAK,YAAA,GAAe,IAAI,gBAAA,CAAiB;AAAA,MACvC,UAAU,OAAA,CAAQ,QAAA;AAAA,MAClB,YAAA,EAAc;AAAA,QACZ,MAAM,UAAA,GAAa;AACjB,UAAA,MAAM,OAAA,GAAU,MAAM,cAAA,CAAe,UAAA,CAAW,OAAO,CAAA;AACvD,UAAA,OAAO,GAAG,OAAO,CAAA,mBAAA,CAAA;AAAA,QACnB;AAAA;AACF,KACD,CAAA;AAED,IAAA,IAAA,CAAK,WAAA,GAAc,IAAI,gBAAA,CAAiB;AAAA,MACtC,UAAU,OAAA,CAAQ,QAAA;AAAA,MAClB,YAAA,EAAc;AAAA,QACZ,MAAM,UAAA,GAAa;AACjB,UAAA,MAAM,OAAA,GAAU,MAAM,cAAA,CAAe,UAAA,CAAW,QAAQ,CAAA;AACxD,UAAA,OAAO,GAAG,OAAO,CAAA,MAAA,CAAA;AAAA,QACnB;AAAA;AACF,KACD,CAAA;AAAA,EACH;AAAA,EAEA,MAAa,sBACX,OAAA,EACgD;AAChD,IAAA,MAAM,2BAAA,GAA8B,YAAY,OAAA,EAAS;AAAA,MACvD,oBAAA,EAAsB,SAAA;AAAA,MACtB,QAAA,EAAU,oBAAoB,iBAAA,CAAkB;AAAA,KACjD,CAAA;AAED,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,WAAA,CAAY,qBAAA;AAAA,MACtC;AAAA,KACF;AAEA,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,IAAI,UAAU,QAAA,CAAS,UAAA;AACvB,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,QAAA,IAAI,IAAA,CAAK,KAAA,EAAO,OAAA,GAAU,IAAA,CAAK,KAAA;AAAA,MACjC,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,IACzB;AAEA,IAAA,OAAO;AAAA,MACL,GAAG,QAAA;AAAA,MACH,MAAM,YAAY;AAChB,QAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,QAAA,MAAM,4BAAA,GAA+B,YAAY,IAAA,EAAM;AAAA,UACrD,oBAAA,EAAsB,SAAA;AAAA,UACtB,QAAA,EACE,oBAAoB,kBAAA,CAAmB;AAAA,SAC1C,CAAA;AACD,QAAA,OAAO,4BAAA;AAAA,MACT;AAAA,KACF;AAAA,EACF;AAAA,EAEA,MAAa,qBAAA,CACX,OAAA,EACA,OAAA,EAC4C;AAC5C,IAAA,MAAM,2BAAA,GAA8B,WAAA;AAAA,MAClC,OAAA;AAAA,MACA;AAAA,KACF;AAGA,IAAA,MAAM,MAAA,GAAS,OAAA,EAAS,KAAA,GAAQ,IAAA,CAAK,eAAe,IAAA,CAAK,WAAA;AAEzD,IAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,qBAAA;AAAA,MAC5B,2BAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,IAAI,UAAU,QAAA,CAAS,UAAA;AACvB,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,QAAA,IAAI,IAAA,CAAK,KAAA,EAAO,OAAA,GAAU,IAAA,CAAK,KAAA;AAAA,MACjC,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,IACzB;AAEA,IAAA,OAAO;AAAA,MACL,GAAG,QAAA;AAAA,MACH,MAAM,YAAY;AAChB,QAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,QAAA,MAAM,4BAAA,GAA+B,WAAA;AAAA,UACnC,IAAA;AAAA,UACA;AAAA,SACF;AACA,QAAA,OAAO,4BAAA;AAAA,MACT;AAAA,KACF;AAAA,EACF;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"OrchestratorSlimClient.cjs.js","sources":["../../../src/clients/orchestrator-slim/OrchestratorSlimClient.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DiscoveryApi,\n FetchApi,\n IdentityApi,\n} from '@backstage/core-plugin-api';\nimport type {\n OrchestratorSlimApi,\n WorkflowAvailabilityResult,\n} from './OrchestratorSlimApi';\nimport type { JsonObject } from '@backstage/types';\n\n/** @public */\nexport class OrchestratorSlimClient implements OrchestratorSlimApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n private baseUrl?: string;\n\n /** @deprecated identityApi is retained for backward compatibility but no longer used. */\n constructor(options: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n identityApi?: IdentityApi;\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi;\n }\n\n async isWorkflowAvailable(workflowId: string): Promise<boolean> {\n const result = await this.checkWorkflowAvailability(workflowId);\n return result.available;\n }\n\n async checkWorkflowAvailability(\n workflowId: string,\n ): Promise<WorkflowAvailabilityResult> {\n if (!workflowId) {\n return {\n available: false,\n reason: 'not_configured',\n errorMessage: 'No workflow configured to apply recommendations',\n };\n }\n\n if (!this.baseUrl) {\n this.baseUrl = await this.discoveryApi.getBaseUrl('orchestrator');\n }\n\n const url = `${this.baseUrl}/v2/workflows/${encodeURIComponent(\n workflowId,\n )}/overview`;\n\n try {\n const response = await this.fetchApi.fetch(url, { method: 'GET' });\n\n if (response.ok) {\n return { available: true };\n }\n\n const statusCode = response.status;\n\n if (statusCode === 404) {\n return {\n available: false,\n reason: 'not_found',\n errorMessage: \"Workflow doesn't exist\",\n };\n }\n\n if (statusCode === 503) {\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Workflow is not available',\n };\n }\n\n if (statusCode === 500) {\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Workflow is not available yet or misconfigured',\n };\n }\n\n if (statusCode === 401 || statusCode === 403) {\n return {\n available: false,\n reason: 'access_denied',\n errorMessage: 'No permission to access the workflow',\n };\n }\n\n // Handle any other error status codes\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Workflow service is currently unavailable',\n };\n } catch (err) {\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Unable to connect to workflow service',\n };\n }\n }\n\n /**\n * Executes a workflow through the cost-management backend which validates\n * inputs and checks ros.apply permission before forwarding to orchestrator.\n * @public\n */\n async executeWorkflow<D = JsonObject>(\n workflowId: string,\n workflowInputData: D,\n ): Promise<{ id: string }> {\n const costManagementBase = await this.discoveryApi.getBaseUrl(\n 'cost-management',\n );\n const url = `${costManagementBase}/apply-recommendation`;\n const response = await this.fetchApi.fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n workflowId,\n ...(workflowInputData as object),\n }),\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n if (!response.ok) {\n const errorPayload = await response.json().catch(() => ({}));\n const message =\n (errorPayload as { error?: string }).error ??\n `Workflow execution failed (${response.status})`;\n throw new Error(message);\n }\n\n return (await response.json()) as { id: string };\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OrchestratorSlimClient.cjs.js","sources":["../../../src/clients/orchestrator-slim/OrchestratorSlimClient.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DiscoveryApi,\n FetchApi,\n IdentityApi,\n} from '@backstage/core-plugin-api';\nimport type {\n OrchestratorSlimApi,\n WorkflowAvailabilityResult,\n} from './OrchestratorSlimApi';\nimport type { JsonObject } from '@backstage/types';\n\n/** @public */\nexport class OrchestratorSlimClient implements OrchestratorSlimApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n private baseUrl?: string;\n\n /** @deprecated identityApi is retained for backward compatibility but no longer used. */\n constructor(options: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n identityApi?: IdentityApi;\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi;\n }\n\n async isWorkflowAvailable(workflowId: string): Promise<boolean> {\n const result = await this.checkWorkflowAvailability(workflowId);\n return result.available;\n }\n\n async checkWorkflowAvailability(\n workflowId: string,\n ): Promise<WorkflowAvailabilityResult> {\n if (!workflowId) {\n return {\n available: false,\n reason: 'not_configured',\n errorMessage: 'No workflow configured to apply recommendations',\n };\n }\n\n if (!this.baseUrl) {\n this.baseUrl = await this.discoveryApi.getBaseUrl('orchestrator');\n }\n\n const url = `${this.baseUrl}/v2/workflows/${encodeURIComponent(\n workflowId,\n )}/overview`;\n\n try {\n const response = await this.fetchApi.fetch(url, { method: 'GET' });\n\n if (response.ok) {\n return { available: true };\n }\n\n const statusCode = response.status;\n\n if (statusCode === 404) {\n return {\n available: false,\n reason: 'not_found',\n errorMessage: \"Workflow doesn't exist\",\n };\n }\n\n if (statusCode === 503) {\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Workflow is not available',\n };\n }\n\n if (statusCode === 500) {\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Workflow is not available yet or misconfigured',\n };\n }\n\n if (statusCode === 401 || statusCode === 403) {\n return {\n available: false,\n reason: 'access_denied',\n errorMessage: 'No permission to access the workflow',\n };\n }\n\n // Handle any other error status codes\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Workflow service is currently unavailable',\n };\n } catch (err) {\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Unable to connect to workflow service',\n };\n }\n }\n\n /**\n * Executes a workflow through the cost-management backend which validates\n * inputs and checks ros.apply permission before forwarding to orchestrator.\n * @public\n */\n async executeWorkflow<D = JsonObject>(\n workflowId: string,\n workflowInputData: D,\n ): Promise<{ id: string }> {\n const costManagementBase = await this.discoveryApi.getBaseUrl(\n 'cost-management',\n );\n const url = `${costManagementBase}/apply-recommendation`;\n const response = await this.fetchApi.fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n workflowId,\n ...(workflowInputData as object),\n }),\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n if (!response.ok) {\n const errorPayload = await response.json().catch(() => ({}));\n const message =\n (errorPayload as { error?: string }).error ??\n `Workflow execution failed (${response.status})`;\n throw new Error(message);\n }\n\n return (await response.json()) as { id: string };\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"OrchestratorSlimClient.esm.js","sources":["../../../src/clients/orchestrator-slim/OrchestratorSlimClient.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DiscoveryApi,\n FetchApi,\n IdentityApi,\n} from '@backstage/core-plugin-api';\nimport type {\n OrchestratorSlimApi,\n WorkflowAvailabilityResult,\n} from './OrchestratorSlimApi';\nimport type { JsonObject } from '@backstage/types';\n\n/** @public */\nexport class OrchestratorSlimClient implements OrchestratorSlimApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n private baseUrl?: string;\n\n /** @deprecated identityApi is retained for backward compatibility but no longer used. */\n constructor(options: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n identityApi?: IdentityApi;\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi;\n }\n\n async isWorkflowAvailable(workflowId: string): Promise<boolean> {\n const result = await this.checkWorkflowAvailability(workflowId);\n return result.available;\n }\n\n async checkWorkflowAvailability(\n workflowId: string,\n ): Promise<WorkflowAvailabilityResult> {\n if (!workflowId) {\n return {\n available: false,\n reason: 'not_configured',\n errorMessage: 'No workflow configured to apply recommendations',\n };\n }\n\n if (!this.baseUrl) {\n this.baseUrl = await this.discoveryApi.getBaseUrl('orchestrator');\n }\n\n const url = `${this.baseUrl}/v2/workflows/${encodeURIComponent(\n workflowId,\n )}/overview`;\n\n try {\n const response = await this.fetchApi.fetch(url, { method: 'GET' });\n\n if (response.ok) {\n return { available: true };\n }\n\n const statusCode = response.status;\n\n if (statusCode === 404) {\n return {\n available: false,\n reason: 'not_found',\n errorMessage: \"Workflow doesn't exist\",\n };\n }\n\n if (statusCode === 503) {\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Workflow is not available',\n };\n }\n\n if (statusCode === 500) {\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Workflow is not available yet or misconfigured',\n };\n }\n\n if (statusCode === 401 || statusCode === 403) {\n return {\n available: false,\n reason: 'access_denied',\n errorMessage: 'No permission to access the workflow',\n };\n }\n\n // Handle any other error status codes\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Workflow service is currently unavailable',\n };\n } catch (err) {\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Unable to connect to workflow service',\n };\n }\n }\n\n /**\n * Executes a workflow through the cost-management backend which validates\n * inputs and checks ros.apply permission before forwarding to orchestrator.\n * @public\n */\n async executeWorkflow<D = JsonObject>(\n workflowId: string,\n workflowInputData: D,\n ): Promise<{ id: string }> {\n const costManagementBase = await this.discoveryApi.getBaseUrl(\n 'cost-management',\n );\n const url = `${costManagementBase}/apply-recommendation`;\n const response = await this.fetchApi.fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n workflowId,\n ...(workflowInputData as object),\n }),\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n if (!response.ok) {\n const errorPayload = await response.json().catch(() => ({}));\n const message =\n (errorPayload as { error?: string }).error ??\n `Workflow execution failed (${response.status})`;\n throw new Error(message);\n }\n\n return (await response.json()) as { id: string };\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OrchestratorSlimClient.esm.js","sources":["../../../src/clients/orchestrator-slim/OrchestratorSlimClient.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DiscoveryApi,\n FetchApi,\n IdentityApi,\n} from '@backstage/core-plugin-api';\nimport type {\n OrchestratorSlimApi,\n WorkflowAvailabilityResult,\n} from './OrchestratorSlimApi';\nimport type { JsonObject } from '@backstage/types';\n\n/** @public */\nexport class OrchestratorSlimClient implements OrchestratorSlimApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n private baseUrl?: string;\n\n /** @deprecated identityApi is retained for backward compatibility but no longer used. */\n constructor(options: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n identityApi?: IdentityApi;\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi;\n }\n\n async isWorkflowAvailable(workflowId: string): Promise<boolean> {\n const result = await this.checkWorkflowAvailability(workflowId);\n return result.available;\n }\n\n async checkWorkflowAvailability(\n workflowId: string,\n ): Promise<WorkflowAvailabilityResult> {\n if (!workflowId) {\n return {\n available: false,\n reason: 'not_configured',\n errorMessage: 'No workflow configured to apply recommendations',\n };\n }\n\n if (!this.baseUrl) {\n this.baseUrl = await this.discoveryApi.getBaseUrl('orchestrator');\n }\n\n const url = `${this.baseUrl}/v2/workflows/${encodeURIComponent(\n workflowId,\n )}/overview`;\n\n try {\n const response = await this.fetchApi.fetch(url, { method: 'GET' });\n\n if (response.ok) {\n return { available: true };\n }\n\n const statusCode = response.status;\n\n if (statusCode === 404) {\n return {\n available: false,\n reason: 'not_found',\n errorMessage: \"Workflow doesn't exist\",\n };\n }\n\n if (statusCode === 503) {\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Workflow is not available',\n };\n }\n\n if (statusCode === 500) {\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Workflow is not available yet or misconfigured',\n };\n }\n\n if (statusCode === 401 || statusCode === 403) {\n return {\n available: false,\n reason: 'access_denied',\n errorMessage: 'No permission to access the workflow',\n };\n }\n\n // Handle any other error status codes\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Workflow service is currently unavailable',\n };\n } catch (err) {\n return {\n available: false,\n reason: 'service_unavailable',\n errorMessage: 'Unable to connect to workflow service',\n };\n }\n }\n\n /**\n * Executes a workflow through the cost-management backend which validates\n * inputs and checks ros.apply permission before forwarding to orchestrator.\n * @public\n */\n async executeWorkflow<D = JsonObject>(\n workflowId: string,\n workflowInputData: D,\n ): Promise<{ id: string }> {\n const costManagementBase = await this.discoveryApi.getBaseUrl(\n 'cost-management',\n );\n const url = `${costManagementBase}/apply-recommendation`;\n const response = await this.fetchApi.fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n workflowId,\n ...(workflowInputData as object),\n }),\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n if (!response.ok) {\n const errorPayload = await response.json().catch(() => ({}));\n const message =\n (errorPayload as { error?: string }).error ??\n `Workflow execution failed (${response.status})`;\n throw new Error(message);\n }\n\n return (await response.json()) as { id: string };\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultApi.client.cjs.js","sources":["../../../src/generated/apis/DefaultApi.client.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// ******************************************************************\n// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *\n// ******************************************************************\nimport { DiscoveryApi } from '../types/discovery';\nimport { FetchApi } from '../types/fetch';\nimport crossFetch from 'cross-fetch';\nimport { pluginId } from '../pluginId';\nimport * as parser from 'uri-template';\n\nimport { RecommendationBoxPlots } from '../models/RecommendationBoxPlots.model';\nimport { RecommendationList } from '../models/RecommendationList.model';\n\n/**\n * Wraps the Response type to convey a type on the json call.\n *\n * @public\n */\nexport type TypedResponse<T> = Omit<Response, 'json'> & {\n json: () => Promise<T>;\n};\n\n/**\n * Options you can pass into a request for additional information.\n *\n * @public\n */\nexport interface RequestOptions {\n token?: string;\n}\n\n/**\n * no description\n * @public\n */\nexport class DefaultApiClient {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: {\n discoveryApi: { getBaseUrl(pluginId: string): Promise<string> };\n fetchApi?: { fetch: typeof fetch };\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi || { fetch: crossFetch };\n }\n\n /**\n * This feature is in limited preview for select customers\n * Get recommendation for container\n * @param recommendationId - The recommendation UUID\n * @param memoryUnit - unit preference for memory\n * @param cpuUnit - unit preference for cpu\n */\n public async getRecommendationById(\n // @ts-ignore\n request: {\n path: {\n recommendationId: string;\n };\n query: {\n memoryUnit?: 'bytes' | 'MiB' | 'GiB';\n cpuUnit?: 'millicores' | 'cores';\n };\n },\n options?: RequestOptions,\n ): Promise<TypedResponse<RecommendationBoxPlots>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n\n const uriTemplate = `/recommendations/openshift/{recommendation_id}{?memory_unit,cpu_unit}`;\n\n const uri = parser.parse(uriTemplate).expand({\n recommendation_id: request.path.recommendationId,\n ...request.query,\n });\n\n return await this.fetchApi.fetch(`${baseUrl}${uri}`, {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'GET',\n });\n }\n\n /**\n * This feature is in limited preview for select customers\n * Get all recommendations\n * @param cluster - Cluster alias or UUID\n * @param workloadType - Options are daemonset, deployment, deploymentconfig, replicaset, replicationcontroller, statefulset\n * @param workload - Workload name\n * @param container - Container name\n * @param project - Project name\n * @param startDate - Start date\n * @param endDate - End date\n * @param offset - Pagination offset\n * @param limit - Pagination limit\n * @param orderBy - Options are cluster, project, workload_type, workload, container, last_reported\n * @param orderHow - Options are ASC, DESC\n */\n public async getRecommendationList(\n // @ts-ignore\n request: {\n query: {\n cluster?: Array<string>;\n workloadType?: Array<string>;\n workload?: Array<string>;\n container?: Array<string>;\n project?: Array<string>;\n startDate?: string;\n endDate?: string;\n offset?: number;\n limit?: number;\n orderBy?:\n | 'cluster'\n | 'project'\n | 'workload_type'\n | 'workload'\n | 'container'\n | 'last_reported';\n orderHow?: 'asc' | 'desc';\n };\n },\n options?: RequestOptions,\n ): Promise<TypedResponse<RecommendationList>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n\n const uriTemplate = `/recommendations/openshift{?cluster*,workload_type*,workload*,container*,project*,start_date,end_date,offset,limit,order_by,order_how}`;\n\n const uri = parser.parse(uriTemplate).expand({\n ...request.query,\n });\n\n return await this.fetchApi.fetch(`${baseUrl}${uri}`, {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'GET',\n });\n }\n}\n"],"names":["crossFetch","pluginId","parser"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDO,MAAM,gBAAiB,CAAA;AAAA,EACX,YAAA;AAAA,EACA,QAAA;AAAA,EAEjB,YAAY,OAGT,EAAA;AACD,IAAA,IAAA,CAAK,eAAe,OAAQ,CAAA,YAAA;AAC5B,IAAA,IAAA,CAAK,QAAW,GAAA,OAAA,CAAQ,QAAY,IAAA,EAAE,OAAOA,2BAAW,EAAA;AAAA;AAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,qBAEX,CAAA,OAAA,EASA,OACgD,EAAA;AAChD,IAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,WAAWC,iBAAQ,CAAA;AAE3D,IAAA,MAAM,WAAc,GAAA,CAAA,qEAAA,CAAA;AAEpB,IAAA,MAAM,GAAM,GAAAC,iBAAA,CAAO,KAAM,CAAA,WAAW,EAAE,MAAO,CAAA;AAAA,MAC3C,iBAAA,EAAmB,QAAQ,IAAK,CAAA,gBAAA;AAAA,MAChC,GAAG,OAAQ,CAAA;AAAA,KACZ,CAAA;AAED,IAAO,OAAA,MAAM,KAAK,QAAS,CAAA,KAAA,CAAM,GAAG,OAAO,CAAA,EAAG,GAAG,CAAI,CAAA,EAAA;AAAA,MACnD,OAAS,EAAA;AAAA,QACP,cAAgB,EAAA,kBAAA;AAAA,QAChB,GAAI,SAAS,KAAS,IAAA,EAAE,eAAe,CAAU,OAAA,EAAA,OAAA,EAAS,KAAK,CAAG,CAAA;AAAA,OACpE;AAAA,MACA,MAAQ,EAAA;AAAA,KACT,CAAA;AAAA;AACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAa,qBAEX,CAAA,OAAA,EAqBA,OAC4C,EAAA;AAC5C,IAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,WAAWD,iBAAQ,CAAA;AAE3D,IAAA,MAAM,WAAc,GAAA,CAAA,sIAAA,CAAA;AAEpB,IAAA,MAAM,GAAM,GAAAC,iBAAA,CAAO,KAAM,CAAA,WAAW,EAAE,MAAO,CAAA;AAAA,MAC3C,GAAG,OAAQ,CAAA;AAAA,KACZ,CAAA;AAED,IAAO,OAAA,MAAM,KAAK,QAAS,CAAA,KAAA,CAAM,GAAG,OAAO,CAAA,EAAG,GAAG,CAAI,CAAA,EAAA;AAAA,MACnD,OAAS,EAAA;AAAA,QACP,cAAgB,EAAA,kBAAA;AAAA,QAChB,GAAI,SAAS,KAAS,IAAA,EAAE,eAAe,CAAU,OAAA,EAAA,OAAA,EAAS,KAAK,CAAG,CAAA;AAAA,OACpE;AAAA,MACA,MAAQ,EAAA;AAAA,KACT,CAAA;AAAA;AAEL;;;;"}
1
+ {"version":3,"file":"DefaultApi.client.cjs.js","sources":["../../../src/generated/apis/DefaultApi.client.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// ******************************************************************\n// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *\n// ******************************************************************\nimport { DiscoveryApi } from '../types/discovery';\nimport { FetchApi } from '../types/fetch';\nimport crossFetch from 'cross-fetch';\nimport { pluginId } from '../pluginId';\nimport * as parser from 'uri-template';\n\nimport { RecommendationBoxPlots } from '../models/RecommendationBoxPlots.model';\nimport { RecommendationList } from '../models/RecommendationList.model';\n\n/**\n * Wraps the Response type to convey a type on the json call.\n *\n * @public\n */\nexport type TypedResponse<T> = Omit<Response, 'json'> & {\n json: () => Promise<T>;\n};\n\n/**\n * Options you can pass into a request for additional information.\n *\n * @public\n */\nexport interface RequestOptions {\n token?: string;\n}\n\n/**\n * no description\n * @public\n */\nexport class DefaultApiClient {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: {\n discoveryApi: { getBaseUrl(pluginId: string): Promise<string> };\n fetchApi?: { fetch: typeof fetch };\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi || { fetch: crossFetch };\n }\n\n /**\n * This feature is in limited preview for select customers\n * Get recommendation for container\n * @param recommendationId - The recommendation UUID\n * @param memoryUnit - unit preference for memory\n * @param cpuUnit - unit preference for cpu\n */\n public async getRecommendationById(\n // @ts-ignore\n request: {\n path: {\n recommendationId: string;\n };\n query: {\n memoryUnit?: 'bytes' | 'MiB' | 'GiB';\n cpuUnit?: 'millicores' | 'cores';\n };\n },\n options?: RequestOptions,\n ): Promise<TypedResponse<RecommendationBoxPlots>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n\n const uriTemplate = `/recommendations/openshift/{recommendation_id}{?memory_unit,cpu_unit}`;\n\n const uri = parser.parse(uriTemplate).expand({\n recommendation_id: request.path.recommendationId,\n ...request.query,\n });\n\n return await this.fetchApi.fetch(`${baseUrl}${uri}`, {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'GET',\n });\n }\n\n /**\n * This feature is in limited preview for select customers\n * Get all recommendations\n * @param cluster - Cluster alias or UUID\n * @param workloadType - Options are daemonset, deployment, deploymentconfig, replicaset, replicationcontroller, statefulset\n * @param workload - Workload name\n * @param container - Container name\n * @param project - Project name\n * @param startDate - Start date\n * @param endDate - End date\n * @param offset - Pagination offset\n * @param limit - Pagination limit\n * @param orderBy - Options are cluster, project, workload_type, workload, container, last_reported\n * @param orderHow - Options are ASC, DESC\n */\n public async getRecommendationList(\n // @ts-ignore\n request: {\n query: {\n cluster?: Array<string>;\n workloadType?: Array<string>;\n workload?: Array<string>;\n container?: Array<string>;\n project?: Array<string>;\n startDate?: string;\n endDate?: string;\n offset?: number;\n limit?: number;\n orderBy?:\n | 'cluster'\n | 'project'\n | 'workload_type'\n | 'workload'\n | 'container'\n | 'last_reported';\n orderHow?: 'asc' | 'desc';\n };\n },\n options?: RequestOptions,\n ): Promise<TypedResponse<RecommendationList>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n\n const uriTemplate = `/recommendations/openshift{?cluster*,workload_type*,workload*,container*,project*,start_date,end_date,offset,limit,order_by,order_how}`;\n\n const uri = parser.parse(uriTemplate).expand({\n ...request.query,\n });\n\n return await this.fetchApi.fetch(`${baseUrl}${uri}`, {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'GET',\n });\n }\n}\n"],"names":["crossFetch","pluginId","parser"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDO,MAAM,gBAAA,CAAiB;AAAA,EACX,YAAA;AAAA,EACA,QAAA;AAAA,EAEjB,YAAY,OAAA,EAGT;AACD,IAAA,IAAA,CAAK,eAAe,OAAA,CAAQ,YAAA;AAC5B,IAAA,IAAA,CAAK,QAAA,GAAW,OAAA,CAAQ,QAAA,IAAY,EAAE,OAAOA,2BAAA,EAAW;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,qBAAA,CAEX,OAAA,EASA,OAAA,EACgD;AAChD,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,YAAA,CAAa,WAAWC,iBAAQ,CAAA;AAE3D,IAAA,MAAM,WAAA,GAAc,CAAA,qEAAA,CAAA;AAEpB,IAAA,MAAM,GAAA,GAAMC,iBAAA,CAAO,KAAA,CAAM,WAAW,EAAE,MAAA,CAAO;AAAA,MAC3C,iBAAA,EAAmB,QAAQ,IAAA,CAAK,gBAAA;AAAA,MAChC,GAAG,OAAA,CAAQ;AAAA,KACZ,CAAA;AAED,IAAA,OAAO,MAAM,KAAK,QAAA,CAAS,KAAA,CAAM,GAAG,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI;AAAA,MACnD,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,GAAI,SAAS,KAAA,IAAS,EAAE,eAAe,CAAA,OAAA,EAAU,OAAA,EAAS,KAAK,CAAA,CAAA;AAAG,OACpE;AAAA,MACA,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAa,qBAAA,CAEX,OAAA,EAqBA,OAAA,EAC4C;AAC5C,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,YAAA,CAAa,WAAWD,iBAAQ,CAAA;AAE3D,IAAA,MAAM,WAAA,GAAc,CAAA,sIAAA,CAAA;AAEpB,IAAA,MAAM,GAAA,GAAMC,iBAAA,CAAO,KAAA,CAAM,WAAW,EAAE,MAAA,CAAO;AAAA,MAC3C,GAAG,OAAA,CAAQ;AAAA,KACZ,CAAA;AAED,IAAA,OAAO,MAAM,KAAK,QAAA,CAAS,KAAA,CAAM,GAAG,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI;AAAA,MACnD,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,GAAI,SAAS,KAAA,IAAS,EAAE,eAAe,CAAA,OAAA,EAAU,OAAA,EAAS,KAAK,CAAA,CAAA;AAAG,OACpE;AAAA,MACA,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultApi.client.esm.js","sources":["../../../src/generated/apis/DefaultApi.client.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// ******************************************************************\n// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *\n// ******************************************************************\nimport { DiscoveryApi } from '../types/discovery';\nimport { FetchApi } from '../types/fetch';\nimport crossFetch from 'cross-fetch';\nimport { pluginId } from '../pluginId';\nimport * as parser from 'uri-template';\n\nimport { RecommendationBoxPlots } from '../models/RecommendationBoxPlots.model';\nimport { RecommendationList } from '../models/RecommendationList.model';\n\n/**\n * Wraps the Response type to convey a type on the json call.\n *\n * @public\n */\nexport type TypedResponse<T> = Omit<Response, 'json'> & {\n json: () => Promise<T>;\n};\n\n/**\n * Options you can pass into a request for additional information.\n *\n * @public\n */\nexport interface RequestOptions {\n token?: string;\n}\n\n/**\n * no description\n * @public\n */\nexport class DefaultApiClient {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: {\n discoveryApi: { getBaseUrl(pluginId: string): Promise<string> };\n fetchApi?: { fetch: typeof fetch };\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi || { fetch: crossFetch };\n }\n\n /**\n * This feature is in limited preview for select customers\n * Get recommendation for container\n * @param recommendationId - The recommendation UUID\n * @param memoryUnit - unit preference for memory\n * @param cpuUnit - unit preference for cpu\n */\n public async getRecommendationById(\n // @ts-ignore\n request: {\n path: {\n recommendationId: string;\n };\n query: {\n memoryUnit?: 'bytes' | 'MiB' | 'GiB';\n cpuUnit?: 'millicores' | 'cores';\n };\n },\n options?: RequestOptions,\n ): Promise<TypedResponse<RecommendationBoxPlots>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n\n const uriTemplate = `/recommendations/openshift/{recommendation_id}{?memory_unit,cpu_unit}`;\n\n const uri = parser.parse(uriTemplate).expand({\n recommendation_id: request.path.recommendationId,\n ...request.query,\n });\n\n return await this.fetchApi.fetch(`${baseUrl}${uri}`, {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'GET',\n });\n }\n\n /**\n * This feature is in limited preview for select customers\n * Get all recommendations\n * @param cluster - Cluster alias or UUID\n * @param workloadType - Options are daemonset, deployment, deploymentconfig, replicaset, replicationcontroller, statefulset\n * @param workload - Workload name\n * @param container - Container name\n * @param project - Project name\n * @param startDate - Start date\n * @param endDate - End date\n * @param offset - Pagination offset\n * @param limit - Pagination limit\n * @param orderBy - Options are cluster, project, workload_type, workload, container, last_reported\n * @param orderHow - Options are ASC, DESC\n */\n public async getRecommendationList(\n // @ts-ignore\n request: {\n query: {\n cluster?: Array<string>;\n workloadType?: Array<string>;\n workload?: Array<string>;\n container?: Array<string>;\n project?: Array<string>;\n startDate?: string;\n endDate?: string;\n offset?: number;\n limit?: number;\n orderBy?:\n | 'cluster'\n | 'project'\n | 'workload_type'\n | 'workload'\n | 'container'\n | 'last_reported';\n orderHow?: 'asc' | 'desc';\n };\n },\n options?: RequestOptions,\n ): Promise<TypedResponse<RecommendationList>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n\n const uriTemplate = `/recommendations/openshift{?cluster*,workload_type*,workload*,container*,project*,start_date,end_date,offset,limit,order_by,order_how}`;\n\n const uri = parser.parse(uriTemplate).expand({\n ...request.query,\n });\n\n return await this.fetchApi.fetch(`${baseUrl}${uri}`, {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'GET',\n });\n }\n}\n"],"names":[],"mappings":";;;;AAkDO,MAAM,gBAAiB,CAAA;AAAA,EACX,YAAA;AAAA,EACA,QAAA;AAAA,EAEjB,YAAY,OAGT,EAAA;AACD,IAAA,IAAA,CAAK,eAAe,OAAQ,CAAA,YAAA;AAC5B,IAAA,IAAA,CAAK,QAAW,GAAA,OAAA,CAAQ,QAAY,IAAA,EAAE,OAAO,UAAW,EAAA;AAAA;AAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,qBAEX,CAAA,OAAA,EASA,OACgD,EAAA;AAChD,IAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,WAAW,QAAQ,CAAA;AAE3D,IAAA,MAAM,WAAc,GAAA,CAAA,qEAAA,CAAA;AAEpB,IAAA,MAAM,GAAM,GAAA,MAAA,CAAO,KAAM,CAAA,WAAW,EAAE,MAAO,CAAA;AAAA,MAC3C,iBAAA,EAAmB,QAAQ,IAAK,CAAA,gBAAA;AAAA,MAChC,GAAG,OAAQ,CAAA;AAAA,KACZ,CAAA;AAED,IAAO,OAAA,MAAM,KAAK,QAAS,CAAA,KAAA,CAAM,GAAG,OAAO,CAAA,EAAG,GAAG,CAAI,CAAA,EAAA;AAAA,MACnD,OAAS,EAAA;AAAA,QACP,cAAgB,EAAA,kBAAA;AAAA,QAChB,GAAI,SAAS,KAAS,IAAA,EAAE,eAAe,CAAU,OAAA,EAAA,OAAA,EAAS,KAAK,CAAG,CAAA;AAAA,OACpE;AAAA,MACA,MAAQ,EAAA;AAAA,KACT,CAAA;AAAA;AACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAa,qBAEX,CAAA,OAAA,EAqBA,OAC4C,EAAA;AAC5C,IAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,WAAW,QAAQ,CAAA;AAE3D,IAAA,MAAM,WAAc,GAAA,CAAA,sIAAA,CAAA;AAEpB,IAAA,MAAM,GAAM,GAAA,MAAA,CAAO,KAAM,CAAA,WAAW,EAAE,MAAO,CAAA;AAAA,MAC3C,GAAG,OAAQ,CAAA;AAAA,KACZ,CAAA;AAED,IAAO,OAAA,MAAM,KAAK,QAAS,CAAA,KAAA,CAAM,GAAG,OAAO,CAAA,EAAG,GAAG,CAAI,CAAA,EAAA;AAAA,MACnD,OAAS,EAAA;AAAA,QACP,cAAgB,EAAA,kBAAA;AAAA,QAChB,GAAI,SAAS,KAAS,IAAA,EAAE,eAAe,CAAU,OAAA,EAAA,OAAA,EAAS,KAAK,CAAG,CAAA;AAAA,OACpE;AAAA,MACA,MAAQ,EAAA;AAAA,KACT,CAAA;AAAA;AAEL;;;;"}
1
+ {"version":3,"file":"DefaultApi.client.esm.js","sources":["../../../src/generated/apis/DefaultApi.client.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// ******************************************************************\n// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *\n// ******************************************************************\nimport { DiscoveryApi } from '../types/discovery';\nimport { FetchApi } from '../types/fetch';\nimport crossFetch from 'cross-fetch';\nimport { pluginId } from '../pluginId';\nimport * as parser from 'uri-template';\n\nimport { RecommendationBoxPlots } from '../models/RecommendationBoxPlots.model';\nimport { RecommendationList } from '../models/RecommendationList.model';\n\n/**\n * Wraps the Response type to convey a type on the json call.\n *\n * @public\n */\nexport type TypedResponse<T> = Omit<Response, 'json'> & {\n json: () => Promise<T>;\n};\n\n/**\n * Options you can pass into a request for additional information.\n *\n * @public\n */\nexport interface RequestOptions {\n token?: string;\n}\n\n/**\n * no description\n * @public\n */\nexport class DefaultApiClient {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: {\n discoveryApi: { getBaseUrl(pluginId: string): Promise<string> };\n fetchApi?: { fetch: typeof fetch };\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi || { fetch: crossFetch };\n }\n\n /**\n * This feature is in limited preview for select customers\n * Get recommendation for container\n * @param recommendationId - The recommendation UUID\n * @param memoryUnit - unit preference for memory\n * @param cpuUnit - unit preference for cpu\n */\n public async getRecommendationById(\n // @ts-ignore\n request: {\n path: {\n recommendationId: string;\n };\n query: {\n memoryUnit?: 'bytes' | 'MiB' | 'GiB';\n cpuUnit?: 'millicores' | 'cores';\n };\n },\n options?: RequestOptions,\n ): Promise<TypedResponse<RecommendationBoxPlots>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n\n const uriTemplate = `/recommendations/openshift/{recommendation_id}{?memory_unit,cpu_unit}`;\n\n const uri = parser.parse(uriTemplate).expand({\n recommendation_id: request.path.recommendationId,\n ...request.query,\n });\n\n return await this.fetchApi.fetch(`${baseUrl}${uri}`, {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'GET',\n });\n }\n\n /**\n * This feature is in limited preview for select customers\n * Get all recommendations\n * @param cluster - Cluster alias or UUID\n * @param workloadType - Options are daemonset, deployment, deploymentconfig, replicaset, replicationcontroller, statefulset\n * @param workload - Workload name\n * @param container - Container name\n * @param project - Project name\n * @param startDate - Start date\n * @param endDate - End date\n * @param offset - Pagination offset\n * @param limit - Pagination limit\n * @param orderBy - Options are cluster, project, workload_type, workload, container, last_reported\n * @param orderHow - Options are ASC, DESC\n */\n public async getRecommendationList(\n // @ts-ignore\n request: {\n query: {\n cluster?: Array<string>;\n workloadType?: Array<string>;\n workload?: Array<string>;\n container?: Array<string>;\n project?: Array<string>;\n startDate?: string;\n endDate?: string;\n offset?: number;\n limit?: number;\n orderBy?:\n | 'cluster'\n | 'project'\n | 'workload_type'\n | 'workload'\n | 'container'\n | 'last_reported';\n orderHow?: 'asc' | 'desc';\n };\n },\n options?: RequestOptions,\n ): Promise<TypedResponse<RecommendationList>> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n\n const uriTemplate = `/recommendations/openshift{?cluster*,workload_type*,workload*,container*,project*,start_date,end_date,offset,limit,order_by,order_how}`;\n\n const uri = parser.parse(uriTemplate).expand({\n ...request.query,\n });\n\n return await this.fetchApi.fetch(`${baseUrl}${uri}`, {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'GET',\n });\n }\n}\n"],"names":[],"mappings":";;;;AAkDO,MAAM,gBAAA,CAAiB;AAAA,EACX,YAAA;AAAA,EACA,QAAA;AAAA,EAEjB,YAAY,OAAA,EAGT;AACD,IAAA,IAAA,CAAK,eAAe,OAAA,CAAQ,YAAA;AAC5B,IAAA,IAAA,CAAK,QAAA,GAAW,OAAA,CAAQ,QAAA,IAAY,EAAE,OAAO,UAAA,EAAW;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,qBAAA,CAEX,OAAA,EASA,OAAA,EACgD;AAChD,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,YAAA,CAAa,WAAW,QAAQ,CAAA;AAE3D,IAAA,MAAM,WAAA,GAAc,CAAA,qEAAA,CAAA;AAEpB,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,KAAA,CAAM,WAAW,EAAE,MAAA,CAAO;AAAA,MAC3C,iBAAA,EAAmB,QAAQ,IAAA,CAAK,gBAAA;AAAA,MAChC,GAAG,OAAA,CAAQ;AAAA,KACZ,CAAA;AAED,IAAA,OAAO,MAAM,KAAK,QAAA,CAAS,KAAA,CAAM,GAAG,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI;AAAA,MACnD,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,GAAI,SAAS,KAAA,IAAS,EAAE,eAAe,CAAA,OAAA,EAAU,OAAA,EAAS,KAAK,CAAA,CAAA;AAAG,OACpE;AAAA,MACA,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAa,qBAAA,CAEX,OAAA,EAqBA,OAAA,EAC4C;AAC5C,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,YAAA,CAAa,WAAW,QAAQ,CAAA;AAE3D,IAAA,MAAM,WAAA,GAAc,CAAA,sIAAA,CAAA;AAEpB,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,KAAA,CAAM,WAAW,EAAE,MAAA,CAAO;AAAA,MAC3C,GAAG,OAAA,CAAQ;AAAA,KACZ,CAAA;AAED,IAAA,OAAO,MAAM,KAAK,QAAA,CAAS,KAAA,CAAM,GAAG,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI;AAAA,MACnD,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,GAAI,SAAS,KAAA,IAAS,EAAE,eAAe,CAAA,OAAA,EAAU,OAAA,EAAS,KAAK,CAAA,CAAA;AAAG,OACpE;AAAA,MACA,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"pluginId.cjs.js","sources":["../../src/generated/pluginId.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @public\n */\nexport const pluginId = 'cost-management';\n"],"names":[],"mappings":";;AAmBO,MAAM,QAAW,GAAA;;;;"}
1
+ {"version":3,"file":"pluginId.cjs.js","sources":["../../src/generated/pluginId.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @public\n */\nexport const pluginId = 'cost-management';\n"],"names":[],"mappings":";;AAmBO,MAAM,QAAA,GAAW;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"pluginId.esm.js","sources":["../../src/generated/pluginId.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @public\n */\nexport const pluginId = 'cost-management';\n"],"names":[],"mappings":"AAmBO,MAAM,QAAW,GAAA;;;;"}
1
+ {"version":3,"file":"pluginId.esm.js","sources":["../../src/generated/pluginId.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @public\n */\nexport const pluginId = 'cost-management';\n"],"names":[],"mappings":"AAmBO,MAAM,QAAA,GAAW;;;;"}
package/dist/index.cjs.js CHANGED
@@ -1,14 +1,14 @@
1
1
  'use strict';
2
2
 
3
- var OptimizationsClient = require('./clients/optimizations/OptimizationsClient.cjs.js');
4
- var OrchestratorSlimClient = require('./clients/orchestrator-slim/OrchestratorSlimClient.cjs.js');
5
3
  var CostManagementSlimClient = require('./clients/cost-management/CostManagementSlimClient.cjs.js');
6
4
  var DefaultApi_client = require('./generated/apis/DefaultApi.client.cjs.js');
5
+ var OptimizationsClient = require('./clients/optimizations/OptimizationsClient.cjs.js');
6
+ var OrchestratorSlimClient = require('./clients/orchestrator-slim/OrchestratorSlimClient.cjs.js');
7
7
 
8
8
 
9
9
 
10
- exports.OptimizationsClient = OptimizationsClient.OptimizationsClient;
11
- exports.OrchestratorSlimClient = OrchestratorSlimClient.OrchestratorSlimClient;
12
10
  exports.CostManagementSlimClient = CostManagementSlimClient.CostManagementSlimClient;
13
11
  exports.DefaultApiClient = DefaultApi_client.DefaultApiClient;
12
+ exports.OptimizationsClient = OptimizationsClient.OptimizationsClient;
13
+ exports.OrchestratorSlimClient = OrchestratorSlimClient.OrchestratorSlimClient;
14
14
  //# sourceMappingURL=index.cjs.js.map
package/dist/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
- export { OptimizationsClient } from './clients/optimizations/OptimizationsClient.esm.js';
2
- export { OrchestratorSlimClient } from './clients/orchestrator-slim/OrchestratorSlimClient.esm.js';
3
1
  export { CostManagementSlimClient } from './clients/cost-management/CostManagementSlimClient.esm.js';
4
2
  export { DefaultApiClient } from './generated/apis/DefaultApi.client.esm.js';
3
+ export { OptimizationsClient } from './clients/optimizations/OptimizationsClient.esm.js';
4
+ export { OrchestratorSlimClient } from './clients/orchestrator-slim/OrchestratorSlimClient.esm.js';
5
5
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"json-utils.cjs.js","sources":["../src/util/mod.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n type JsonValue,\n maybeJsonArray,\n maybeJsonObject,\n maybeJsonValue,\n} from './lib/json';\nimport { JsonNode, type JsonNodeVisitorOptions } from './lib/json_node';\n\n/**\n * Recursively transforms the keys of JSON objects within the input value using the provided function.\n *\n * @public\n * @param input - The input value to process. Must be a valid JSON value.\n * @param functionOrOptions - A function that can be used to change the keys in the provided input or a configuration object.\n * @throws \\{TypeError\\} If the input is not a valid JSON value.\n *\n * @returns The same value when the input is a JSON scalar, an empty array or empty object; otherwise a new reference value.\n */\nexport function deepMapKeys(\n input: unknown,\n functionOrOptions:\n | JsonNodeVisitorOptions\n | JsonNodeVisitorOptions['onVisitJsonObjectKey'],\n): JsonValue {\n if (!maybeJsonValue(input)) {\n throw new TypeError('Invalid argument type');\n }\n\n if (\n (maybeJsonObject(input) && Object.keys(input).length === 0) ||\n (maybeJsonArray(input) && input.length === 0)\n ) {\n return input;\n }\n\n const node = new JsonNode('$', input);\n const visitor = new JsonNode.Visitor(\n typeof functionOrOptions === 'function'\n ? { onVisitJsonObjectKey: functionOrOptions }\n : functionOrOptions,\n );\n node.accept(visitor);\n\n return node.toJsonValue();\n}\n"],"names":["maybeJsonValue","maybeJsonObject","maybeJsonArray","JsonNode"],"mappings":";;;;;AAkCgB,SAAA,WAAA,CACd,OACA,iBAGW,EAAA;AACX,EAAI,IAAA,CAACA,mBAAe,CAAA,KAAK,CAAG,EAAA;AAC1B,IAAM,MAAA,IAAI,UAAU,uBAAuB,CAAA;AAAA;AAG7C,EAAA,IACGC,oBAAgB,CAAA,KAAK,CAAK,IAAA,MAAA,CAAO,KAAK,KAAK,CAAA,CAAE,MAAW,KAAA,CAAA,IACxDC,mBAAe,CAAA,KAAK,CAAK,IAAA,KAAA,CAAM,WAAW,CAC3C,EAAA;AACA,IAAO,OAAA,KAAA;AAAA;AAGT,EAAA,MAAM,IAAO,GAAA,IAAIC,kBAAS,CAAA,GAAA,EAAK,KAAK,CAAA;AACpC,EAAM,MAAA,OAAA,GAAU,IAAIA,kBAAS,CAAA,OAAA;AAAA,IAC3B,OAAO,iBAAsB,KAAA,UAAA,GACzB,EAAE,oBAAA,EAAsB,mBACxB,GAAA;AAAA,GACN;AACA,EAAA,IAAA,CAAK,OAAO,OAAO,CAAA;AAEnB,EAAA,OAAO,KAAK,WAAY,EAAA;AAC1B;;;;"}
1
+ {"version":3,"file":"json-utils.cjs.js","sources":["../src/util/mod.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n type JsonValue,\n maybeJsonArray,\n maybeJsonObject,\n maybeJsonValue,\n} from './lib/json';\nimport { JsonNode, type JsonNodeVisitorOptions } from './lib/json_node';\n\n/**\n * Recursively transforms the keys of JSON objects within the input value using the provided function.\n *\n * @public\n * @param input - The input value to process. Must be a valid JSON value.\n * @param functionOrOptions - A function that can be used to change the keys in the provided input or a configuration object.\n * @throws \\{TypeError\\} If the input is not a valid JSON value.\n *\n * @returns The same value when the input is a JSON scalar, an empty array or empty object; otherwise a new reference value.\n */\nexport function deepMapKeys(\n input: unknown,\n functionOrOptions:\n | JsonNodeVisitorOptions\n | JsonNodeVisitorOptions['onVisitJsonObjectKey'],\n): JsonValue {\n if (!maybeJsonValue(input)) {\n throw new TypeError('Invalid argument type');\n }\n\n if (\n (maybeJsonObject(input) && Object.keys(input).length === 0) ||\n (maybeJsonArray(input) && input.length === 0)\n ) {\n return input;\n }\n\n const node = new JsonNode('$', input);\n const visitor = new JsonNode.Visitor(\n typeof functionOrOptions === 'function'\n ? { onVisitJsonObjectKey: functionOrOptions }\n : functionOrOptions,\n );\n node.accept(visitor);\n\n return node.toJsonValue();\n}\n"],"names":["maybeJsonValue","maybeJsonObject","maybeJsonArray","JsonNode"],"mappings":";;;;;AAkCO,SAAS,WAAA,CACd,OACA,iBAAA,EAGW;AACX,EAAA,IAAI,CAACA,mBAAA,CAAe,KAAK,CAAA,EAAG;AAC1B,IAAA,MAAM,IAAI,UAAU,uBAAuB,CAAA;AAAA,EAC7C;AAEA,EAAA,IACGC,oBAAA,CAAgB,KAAK,CAAA,IAAK,MAAA,CAAO,KAAK,KAAK,CAAA,CAAE,MAAA,KAAW,CAAA,IACxDC,mBAAA,CAAe,KAAK,CAAA,IAAK,KAAA,CAAM,WAAW,CAAA,EAC3C;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,IAAA,GAAO,IAAIC,kBAAA,CAAS,GAAA,EAAK,KAAK,CAAA;AACpC,EAAA,MAAM,OAAA,GAAU,IAAIA,kBAAA,CAAS,OAAA;AAAA,IAC3B,OAAO,iBAAA,KAAsB,UAAA,GACzB,EAAE,oBAAA,EAAsB,mBAAkB,GAC1C;AAAA,GACN;AACA,EAAA,IAAA,CAAK,OAAO,OAAO,CAAA;AAEnB,EAAA,OAAO,KAAK,WAAA,EAAY;AAC1B;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"json-utils.esm.js","sources":["../src/util/mod.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n type JsonValue,\n maybeJsonArray,\n maybeJsonObject,\n maybeJsonValue,\n} from './lib/json';\nimport { JsonNode, type JsonNodeVisitorOptions } from './lib/json_node';\n\n/**\n * Recursively transforms the keys of JSON objects within the input value using the provided function.\n *\n * @public\n * @param input - The input value to process. Must be a valid JSON value.\n * @param functionOrOptions - A function that can be used to change the keys in the provided input or a configuration object.\n * @throws \\{TypeError\\} If the input is not a valid JSON value.\n *\n * @returns The same value when the input is a JSON scalar, an empty array or empty object; otherwise a new reference value.\n */\nexport function deepMapKeys(\n input: unknown,\n functionOrOptions:\n | JsonNodeVisitorOptions\n | JsonNodeVisitorOptions['onVisitJsonObjectKey'],\n): JsonValue {\n if (!maybeJsonValue(input)) {\n throw new TypeError('Invalid argument type');\n }\n\n if (\n (maybeJsonObject(input) && Object.keys(input).length === 0) ||\n (maybeJsonArray(input) && input.length === 0)\n ) {\n return input;\n }\n\n const node = new JsonNode('$', input);\n const visitor = new JsonNode.Visitor(\n typeof functionOrOptions === 'function'\n ? { onVisitJsonObjectKey: functionOrOptions }\n : functionOrOptions,\n );\n node.accept(visitor);\n\n return node.toJsonValue();\n}\n"],"names":[],"mappings":";;;AAkCgB,SAAA,WAAA,CACd,OACA,iBAGW,EAAA;AACX,EAAI,IAAA,CAAC,cAAe,CAAA,KAAK,CAAG,EAAA;AAC1B,IAAM,MAAA,IAAI,UAAU,uBAAuB,CAAA;AAAA;AAG7C,EAAA,IACG,eAAgB,CAAA,KAAK,CAAK,IAAA,MAAA,CAAO,KAAK,KAAK,CAAA,CAAE,MAAW,KAAA,CAAA,IACxD,cAAe,CAAA,KAAK,CAAK,IAAA,KAAA,CAAM,WAAW,CAC3C,EAAA;AACA,IAAO,OAAA,KAAA;AAAA;AAGT,EAAA,MAAM,IAAO,GAAA,IAAI,QAAS,CAAA,GAAA,EAAK,KAAK,CAAA;AACpC,EAAM,MAAA,OAAA,GAAU,IAAI,QAAS,CAAA,OAAA;AAAA,IAC3B,OAAO,iBAAsB,KAAA,UAAA,GACzB,EAAE,oBAAA,EAAsB,mBACxB,GAAA;AAAA,GACN;AACA,EAAA,IAAA,CAAK,OAAO,OAAO,CAAA;AAEnB,EAAA,OAAO,KAAK,WAAY,EAAA;AAC1B;;;;"}
1
+ {"version":3,"file":"json-utils.esm.js","sources":["../src/util/mod.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n type JsonValue,\n maybeJsonArray,\n maybeJsonObject,\n maybeJsonValue,\n} from './lib/json';\nimport { JsonNode, type JsonNodeVisitorOptions } from './lib/json_node';\n\n/**\n * Recursively transforms the keys of JSON objects within the input value using the provided function.\n *\n * @public\n * @param input - The input value to process. Must be a valid JSON value.\n * @param functionOrOptions - A function that can be used to change the keys in the provided input or a configuration object.\n * @throws \\{TypeError\\} If the input is not a valid JSON value.\n *\n * @returns The same value when the input is a JSON scalar, an empty array or empty object; otherwise a new reference value.\n */\nexport function deepMapKeys(\n input: unknown,\n functionOrOptions:\n | JsonNodeVisitorOptions\n | JsonNodeVisitorOptions['onVisitJsonObjectKey'],\n): JsonValue {\n if (!maybeJsonValue(input)) {\n throw new TypeError('Invalid argument type');\n }\n\n if (\n (maybeJsonObject(input) && Object.keys(input).length === 0) ||\n (maybeJsonArray(input) && input.length === 0)\n ) {\n return input;\n }\n\n const node = new JsonNode('$', input);\n const visitor = new JsonNode.Visitor(\n typeof functionOrOptions === 'function'\n ? { onVisitJsonObjectKey: functionOrOptions }\n : functionOrOptions,\n );\n node.accept(visitor);\n\n return node.toJsonValue();\n}\n"],"names":[],"mappings":";;;AAkCO,SAAS,WAAA,CACd,OACA,iBAAA,EAGW;AACX,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,CAAA,EAAG;AAC1B,IAAA,MAAM,IAAI,UAAU,uBAAuB,CAAA;AAAA,EAC7C;AAEA,EAAA,IACG,eAAA,CAAgB,KAAK,CAAA,IAAK,MAAA,CAAO,KAAK,KAAK,CAAA,CAAE,MAAA,KAAW,CAAA,IACxD,cAAA,CAAe,KAAK,CAAA,IAAK,KAAA,CAAM,WAAW,CAAA,EAC3C;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,IAAA,GAAO,IAAI,QAAA,CAAS,GAAA,EAAK,KAAK,CAAA;AACpC,EAAA,MAAM,OAAA,GAAU,IAAI,QAAA,CAAS,OAAA;AAAA,IAC3B,OAAO,iBAAA,KAAsB,UAAA,GACzB,EAAE,oBAAA,EAAsB,mBAAkB,GAC1C;AAAA,GACN;AACA,EAAA,IAAA,CAAK,OAAO,OAAO,CAAA;AAEnB,EAAA,OAAO,KAAK,WAAA,EAAY;AAC1B;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"permissions.cjs.js","sources":["../src/permissions.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createPermission } from '@backstage/plugin-permission-common';\n\n/** @public */\nexport const rosPluginReadPermission = createPermission({\n name: 'ros.plugin',\n attributes: { action: 'read' },\n});\n\n/** @public */\nexport const rosApplyPermission = createPermission({\n name: 'ros.apply',\n attributes: { action: 'update' },\n});\n\n/** @public */\nexport const rosClusterSpecificPermission = (clusterName: string) =>\n createPermission({\n name: `ros/${clusterName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const rosClusterProjectPermission = (\n clusterName: string,\n projectName: string,\n) =>\n createPermission({\n name: `ros/${clusterName}/${projectName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const costPluginReadPermission = createPermission({\n name: 'cost.plugin',\n attributes: { action: 'read' },\n});\n\n/** @public */\nexport const costClusterSpecificPermission = (clusterName: string) =>\n createPermission({\n name: `cost/${clusterName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const costClusterProjectPermission = (\n clusterName: string,\n projectName: string,\n) =>\n createPermission({\n name: `cost/${clusterName}/${projectName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const costPluginPermissions = [costPluginReadPermission];\n\n/** @public */\nexport const rosPluginPermissions = [rosPluginReadPermission];\n\n/** @public */\nexport const rosApplyPermissions = [rosApplyPermission];\n"],"names":["createPermission"],"mappings":";;;;AAmBO,MAAM,0BAA0BA,uCAAiB,CAAA;AAAA,EACtD,IAAM,EAAA,YAAA;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAO;AAC/B,CAAC;AAGM,MAAM,qBAAqBA,uCAAiB,CAAA;AAAA,EACjD,IAAM,EAAA,WAAA;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAQ,QAAS;AACjC,CAAC;AAGY,MAAA,4BAAA,GAA+B,CAAC,WAAA,KAC3CA,uCAAiB,CAAA;AAAA,EACf,IAAA,EAAM,OAAO,WAAW,CAAA,CAAA;AAAA,EACxB,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAO;AAC/B,CAAC;AAGI,MAAM,2BAA8B,GAAA,CACzC,WACA,EAAA,WAAA,KAEAA,uCAAiB,CAAA;AAAA,EACf,IAAM,EAAA,CAAA,IAAA,EAAO,WAAW,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA;AAAA,EACvC,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAO;AAC/B,CAAC;AAGI,MAAM,2BAA2BA,uCAAiB,CAAA;AAAA,EACvD,IAAM,EAAA,aAAA;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAO;AAC/B,CAAC;AAGY,MAAA,6BAAA,GAAgC,CAAC,WAAA,KAC5CA,uCAAiB,CAAA;AAAA,EACf,IAAA,EAAM,QAAQ,WAAW,CAAA,CAAA;AAAA,EACzB,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAO;AAC/B,CAAC;AAGI,MAAM,4BAA+B,GAAA,CAC1C,WACA,EAAA,WAAA,KAEAA,uCAAiB,CAAA;AAAA,EACf,IAAM,EAAA,CAAA,KAAA,EAAQ,WAAW,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA;AAAA,EACxC,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAO;AAC/B,CAAC;AAGU,MAAA,qBAAA,GAAwB,CAAC,wBAAwB;AAGjD,MAAA,oBAAA,GAAuB,CAAC,uBAAuB;AAG/C,MAAA,mBAAA,GAAsB,CAAC,kBAAkB;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"permissions.cjs.js","sources":["../src/permissions.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createPermission } from '@backstage/plugin-permission-common';\n\n/** @public */\nexport const rosPluginReadPermission = createPermission({\n name: 'ros.plugin',\n attributes: { action: 'read' },\n});\n\n/** @public */\nexport const rosApplyPermission = createPermission({\n name: 'ros.apply',\n attributes: { action: 'update' },\n});\n\n/** @public */\nexport const rosClusterSpecificPermission = (clusterName: string) =>\n createPermission({\n name: `ros/${clusterName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const rosClusterProjectPermission = (\n clusterName: string,\n projectName: string,\n) =>\n createPermission({\n name: `ros/${clusterName}/${projectName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const costPluginReadPermission = createPermission({\n name: 'cost.plugin',\n attributes: { action: 'read' },\n});\n\n/** @public */\nexport const costClusterSpecificPermission = (clusterName: string) =>\n createPermission({\n name: `cost/${clusterName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const costClusterProjectPermission = (\n clusterName: string,\n projectName: string,\n) =>\n createPermission({\n name: `cost/${clusterName}/${projectName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const costPluginPermissions = [costPluginReadPermission];\n\n/** @public */\nexport const rosPluginPermissions = [rosPluginReadPermission];\n\n/** @public */\nexport const rosApplyPermissions = [rosApplyPermission];\n"],"names":["createPermission"],"mappings":";;;;AAmBO,MAAM,0BAA0BA,uCAAA,CAAiB;AAAA,EACtD,IAAA,EAAM,YAAA;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA;AACxB,CAAC;AAGM,MAAM,qBAAqBA,uCAAA,CAAiB;AAAA,EACjD,IAAA,EAAM,WAAA;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAQ,QAAA;AACxB,CAAC;AAGM,MAAM,4BAAA,GAA+B,CAAC,WAAA,KAC3CA,uCAAA,CAAiB;AAAA,EACf,IAAA,EAAM,OAAO,WAAW,CAAA,CAAA;AAAA,EACxB,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA;AACxB,CAAC;AAGI,MAAM,2BAAA,GAA8B,CACzC,WAAA,EACA,WAAA,KAEAA,uCAAA,CAAiB;AAAA,EACf,IAAA,EAAM,CAAA,IAAA,EAAO,WAAW,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA;AAAA,EACvC,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA;AACxB,CAAC;AAGI,MAAM,2BAA2BA,uCAAA,CAAiB;AAAA,EACvD,IAAA,EAAM,aAAA;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA;AACxB,CAAC;AAGM,MAAM,6BAAA,GAAgC,CAAC,WAAA,KAC5CA,uCAAA,CAAiB;AAAA,EACf,IAAA,EAAM,QAAQ,WAAW,CAAA,CAAA;AAAA,EACzB,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA;AACxB,CAAC;AAGI,MAAM,4BAAA,GAA+B,CAC1C,WAAA,EACA,WAAA,KAEAA,uCAAA,CAAiB;AAAA,EACf,IAAA,EAAM,CAAA,KAAA,EAAQ,WAAW,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA;AAAA,EACxC,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA;AACxB,CAAC;AAGI,MAAM,qBAAA,GAAwB,CAAC,wBAAwB;AAGvD,MAAM,oBAAA,GAAuB,CAAC,uBAAuB;AAGrD,MAAM,mBAAA,GAAsB,CAAC,kBAAkB;;;;;;;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"permissions.esm.js","sources":["../src/permissions.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createPermission } from '@backstage/plugin-permission-common';\n\n/** @public */\nexport const rosPluginReadPermission = createPermission({\n name: 'ros.plugin',\n attributes: { action: 'read' },\n});\n\n/** @public */\nexport const rosApplyPermission = createPermission({\n name: 'ros.apply',\n attributes: { action: 'update' },\n});\n\n/** @public */\nexport const rosClusterSpecificPermission = (clusterName: string) =>\n createPermission({\n name: `ros/${clusterName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const rosClusterProjectPermission = (\n clusterName: string,\n projectName: string,\n) =>\n createPermission({\n name: `ros/${clusterName}/${projectName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const costPluginReadPermission = createPermission({\n name: 'cost.plugin',\n attributes: { action: 'read' },\n});\n\n/** @public */\nexport const costClusterSpecificPermission = (clusterName: string) =>\n createPermission({\n name: `cost/${clusterName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const costClusterProjectPermission = (\n clusterName: string,\n projectName: string,\n) =>\n createPermission({\n name: `cost/${clusterName}/${projectName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const costPluginPermissions = [costPluginReadPermission];\n\n/** @public */\nexport const rosPluginPermissions = [rosPluginReadPermission];\n\n/** @public */\nexport const rosApplyPermissions = [rosApplyPermission];\n"],"names":[],"mappings":";;AAmBO,MAAM,0BAA0B,gBAAiB,CAAA;AAAA,EACtD,IAAM,EAAA,YAAA;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAO;AAC/B,CAAC;AAGM,MAAM,qBAAqB,gBAAiB,CAAA;AAAA,EACjD,IAAM,EAAA,WAAA;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAQ,QAAS;AACjC,CAAC;AAGY,MAAA,4BAAA,GAA+B,CAAC,WAAA,KAC3C,gBAAiB,CAAA;AAAA,EACf,IAAA,EAAM,OAAO,WAAW,CAAA,CAAA;AAAA,EACxB,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAO;AAC/B,CAAC;AAGI,MAAM,2BAA8B,GAAA,CACzC,WACA,EAAA,WAAA,KAEA,gBAAiB,CAAA;AAAA,EACf,IAAM,EAAA,CAAA,IAAA,EAAO,WAAW,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA;AAAA,EACvC,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAO;AAC/B,CAAC;AAGI,MAAM,2BAA2B,gBAAiB,CAAA;AAAA,EACvD,IAAM,EAAA,aAAA;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAO;AAC/B,CAAC;AAGY,MAAA,6BAAA,GAAgC,CAAC,WAAA,KAC5C,gBAAiB,CAAA;AAAA,EACf,IAAA,EAAM,QAAQ,WAAW,CAAA,CAAA;AAAA,EACzB,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAO;AAC/B,CAAC;AAGI,MAAM,4BAA+B,GAAA,CAC1C,WACA,EAAA,WAAA,KAEA,gBAAiB,CAAA;AAAA,EACf,IAAM,EAAA,CAAA,KAAA,EAAQ,WAAW,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA;AAAA,EACxC,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAO;AAC/B,CAAC;AAGU,MAAA,qBAAA,GAAwB,CAAC,wBAAwB;AAGjD,MAAA,oBAAA,GAAuB,CAAC,uBAAuB;AAG/C,MAAA,mBAAA,GAAsB,CAAC,kBAAkB;;;;"}
1
+ {"version":3,"file":"permissions.esm.js","sources":["../src/permissions.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createPermission } from '@backstage/plugin-permission-common';\n\n/** @public */\nexport const rosPluginReadPermission = createPermission({\n name: 'ros.plugin',\n attributes: { action: 'read' },\n});\n\n/** @public */\nexport const rosApplyPermission = createPermission({\n name: 'ros.apply',\n attributes: { action: 'update' },\n});\n\n/** @public */\nexport const rosClusterSpecificPermission = (clusterName: string) =>\n createPermission({\n name: `ros/${clusterName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const rosClusterProjectPermission = (\n clusterName: string,\n projectName: string,\n) =>\n createPermission({\n name: `ros/${clusterName}/${projectName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const costPluginReadPermission = createPermission({\n name: 'cost.plugin',\n attributes: { action: 'read' },\n});\n\n/** @public */\nexport const costClusterSpecificPermission = (clusterName: string) =>\n createPermission({\n name: `cost/${clusterName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const costClusterProjectPermission = (\n clusterName: string,\n projectName: string,\n) =>\n createPermission({\n name: `cost/${clusterName}/${projectName}`,\n attributes: { action: 'read' },\n });\n\n/** @public */\nexport const costPluginPermissions = [costPluginReadPermission];\n\n/** @public */\nexport const rosPluginPermissions = [rosPluginReadPermission];\n\n/** @public */\nexport const rosApplyPermissions = [rosApplyPermission];\n"],"names":[],"mappings":";;AAmBO,MAAM,0BAA0B,gBAAA,CAAiB;AAAA,EACtD,IAAA,EAAM,YAAA;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA;AACxB,CAAC;AAGM,MAAM,qBAAqB,gBAAA,CAAiB;AAAA,EACjD,IAAA,EAAM,WAAA;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAQ,QAAA;AACxB,CAAC;AAGM,MAAM,4BAAA,GAA+B,CAAC,WAAA,KAC3C,gBAAA,CAAiB;AAAA,EACf,IAAA,EAAM,OAAO,WAAW,CAAA,CAAA;AAAA,EACxB,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA;AACxB,CAAC;AAGI,MAAM,2BAAA,GAA8B,CACzC,WAAA,EACA,WAAA,KAEA,gBAAA,CAAiB;AAAA,EACf,IAAA,EAAM,CAAA,IAAA,EAAO,WAAW,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA;AAAA,EACvC,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA;AACxB,CAAC;AAGI,MAAM,2BAA2B,gBAAA,CAAiB;AAAA,EACvD,IAAA,EAAM,aAAA;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA;AACxB,CAAC;AAGM,MAAM,6BAAA,GAAgC,CAAC,WAAA,KAC5C,gBAAA,CAAiB;AAAA,EACf,IAAA,EAAM,QAAQ,WAAW,CAAA,CAAA;AAAA,EACzB,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA;AACxB,CAAC;AAGI,MAAM,4BAAA,GAA+B,CAC1C,WAAA,EACA,WAAA,KAEA,gBAAA,CAAiB;AAAA,EACf,IAAA,EAAM,CAAA,KAAA,EAAQ,WAAW,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA;AAAA,EACxC,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA;AACxB,CAAC;AAGI,MAAM,qBAAA,GAAwB,CAAC,wBAAwB;AAGvD,MAAM,oBAAA,GAAuB,CAAC,uBAAuB;AAGrD,MAAM,mBAAA,GAAsB,CAAC,kBAAkB;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"json.cjs.js","sources":["../../../src/util/lib/json.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport type JsonScalar = number | string | boolean | null;\n\n/** Asserts `value` is a JsonScalar */\nexport function isJsonScalar(value: unknown): value is JsonScalar {\n return (\n typeof value === 'number' ||\n typeof value === 'string' ||\n typeof value === 'boolean' ||\n value === null\n );\n}\n\n/** A type representing a JSON object */\nexport type JsonObject = {\n [key in string]?: JsonValue;\n};\n\n/** Asserts non-recursively that `value` may be a JsonObject */\nexport function maybeJsonObject(value: unknown): value is JsonObject {\n return value?.constructor.name === 'Object';\n}\n\n/** A type representing JSON array */\nexport type JsonArray = Array<JsonValue>;\n\n/** Asserts non-recursively that `value` may be a JsonArray */\nexport function maybeJsonArray(value: unknown): value is JsonArray {\n return Array.isArray(value);\n}\n\n/** A type representing all valid JSON serializable values. */\nexport type JsonValue = JsonObject | JsonArray | JsonScalar;\n\n/** Asserts that `value` may be a JsonValue */\nexport function maybeJsonValue(value: unknown): value is JsonValue {\n return (\n typeof value !== 'undefined' &&\n (isJsonScalar(value) || maybeJsonObject(value) || maybeJsonArray(value))\n );\n}\n"],"names":[],"mappings":";;AAmBO,SAAS,aAAa,KAAqC,EAAA;AAChE,EACE,OAAA,OAAO,UAAU,QACjB,IAAA,OAAO,UAAU,QACjB,IAAA,OAAO,KAAU,KAAA,SAAA,IACjB,KAAU,KAAA,IAAA;AAEd;AAQO,SAAS,gBAAgB,KAAqC,EAAA;AACnE,EAAO,OAAA,KAAA,EAAO,YAAY,IAAS,KAAA,QAAA;AACrC;AAMO,SAAS,eAAe,KAAoC,EAAA;AACjE,EAAO,OAAA,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC5B;AAMO,SAAS,eAAe,KAAoC,EAAA;AACjE,EACE,OAAA,OAAO,KAAU,KAAA,WAAA,KAChB,YAAa,CAAA,KAAK,KAAK,eAAgB,CAAA,KAAK,CAAK,IAAA,cAAA,CAAe,KAAK,CAAA,CAAA;AAE1E;;;;;;;"}
1
+ {"version":3,"file":"json.cjs.js","sources":["../../../src/util/lib/json.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport type JsonScalar = number | string | boolean | null;\n\n/** Asserts `value` is a JsonScalar */\nexport function isJsonScalar(value: unknown): value is JsonScalar {\n return (\n typeof value === 'number' ||\n typeof value === 'string' ||\n typeof value === 'boolean' ||\n value === null\n );\n}\n\n/** A type representing a JSON object */\nexport type JsonObject = {\n [key in string]?: JsonValue;\n};\n\n/** Asserts non-recursively that `value` may be a JsonObject */\nexport function maybeJsonObject(value: unknown): value is JsonObject {\n return value?.constructor.name === 'Object';\n}\n\n/** A type representing JSON array */\nexport type JsonArray = Array<JsonValue>;\n\n/** Asserts non-recursively that `value` may be a JsonArray */\nexport function maybeJsonArray(value: unknown): value is JsonArray {\n return Array.isArray(value);\n}\n\n/** A type representing all valid JSON serializable values. */\nexport type JsonValue = JsonObject | JsonArray | JsonScalar;\n\n/** Asserts that `value` may be a JsonValue */\nexport function maybeJsonValue(value: unknown): value is JsonValue {\n return (\n typeof value !== 'undefined' &&\n (isJsonScalar(value) || maybeJsonObject(value) || maybeJsonArray(value))\n );\n}\n"],"names":[],"mappings":";;AAmBO,SAAS,aAAa,KAAA,EAAqC;AAChE,EAAA,OACE,OAAO,UAAU,QAAA,IACjB,OAAO,UAAU,QAAA,IACjB,OAAO,KAAA,KAAU,SAAA,IACjB,KAAA,KAAU,IAAA;AAEd;AAQO,SAAS,gBAAgB,KAAA,EAAqC;AACnE,EAAA,OAAO,KAAA,EAAO,YAAY,IAAA,KAAS,QAAA;AACrC;AAMO,SAAS,eAAe,KAAA,EAAoC;AACjE,EAAA,OAAO,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC5B;AAMO,SAAS,eAAe,KAAA,EAAoC;AACjE,EAAA,OACE,OAAO,KAAA,KAAU,WAAA,KAChB,YAAA,CAAa,KAAK,KAAK,eAAA,CAAgB,KAAK,CAAA,IAAK,cAAA,CAAe,KAAK,CAAA,CAAA;AAE1E;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"json.esm.js","sources":["../../../src/util/lib/json.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport type JsonScalar = number | string | boolean | null;\n\n/** Asserts `value` is a JsonScalar */\nexport function isJsonScalar(value: unknown): value is JsonScalar {\n return (\n typeof value === 'number' ||\n typeof value === 'string' ||\n typeof value === 'boolean' ||\n value === null\n );\n}\n\n/** A type representing a JSON object */\nexport type JsonObject = {\n [key in string]?: JsonValue;\n};\n\n/** Asserts non-recursively that `value` may be a JsonObject */\nexport function maybeJsonObject(value: unknown): value is JsonObject {\n return value?.constructor.name === 'Object';\n}\n\n/** A type representing JSON array */\nexport type JsonArray = Array<JsonValue>;\n\n/** Asserts non-recursively that `value` may be a JsonArray */\nexport function maybeJsonArray(value: unknown): value is JsonArray {\n return Array.isArray(value);\n}\n\n/** A type representing all valid JSON serializable values. */\nexport type JsonValue = JsonObject | JsonArray | JsonScalar;\n\n/** Asserts that `value` may be a JsonValue */\nexport function maybeJsonValue(value: unknown): value is JsonValue {\n return (\n typeof value !== 'undefined' &&\n (isJsonScalar(value) || maybeJsonObject(value) || maybeJsonArray(value))\n );\n}\n"],"names":[],"mappings":"AAmBO,SAAS,aAAa,KAAqC,EAAA;AAChE,EACE,OAAA,OAAO,UAAU,QACjB,IAAA,OAAO,UAAU,QACjB,IAAA,OAAO,KAAU,KAAA,SAAA,IACjB,KAAU,KAAA,IAAA;AAEd;AAQO,SAAS,gBAAgB,KAAqC,EAAA;AACnE,EAAO,OAAA,KAAA,EAAO,YAAY,IAAS,KAAA,QAAA;AACrC;AAMO,SAAS,eAAe,KAAoC,EAAA;AACjE,EAAO,OAAA,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC5B;AAMO,SAAS,eAAe,KAAoC,EAAA;AACjE,EACE,OAAA,OAAO,KAAU,KAAA,WAAA,KAChB,YAAa,CAAA,KAAK,KAAK,eAAgB,CAAA,KAAK,CAAK,IAAA,cAAA,CAAe,KAAK,CAAA,CAAA;AAE1E;;;;"}
1
+ {"version":3,"file":"json.esm.js","sources":["../../../src/util/lib/json.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport type JsonScalar = number | string | boolean | null;\n\n/** Asserts `value` is a JsonScalar */\nexport function isJsonScalar(value: unknown): value is JsonScalar {\n return (\n typeof value === 'number' ||\n typeof value === 'string' ||\n typeof value === 'boolean' ||\n value === null\n );\n}\n\n/** A type representing a JSON object */\nexport type JsonObject = {\n [key in string]?: JsonValue;\n};\n\n/** Asserts non-recursively that `value` may be a JsonObject */\nexport function maybeJsonObject(value: unknown): value is JsonObject {\n return value?.constructor.name === 'Object';\n}\n\n/** A type representing JSON array */\nexport type JsonArray = Array<JsonValue>;\n\n/** Asserts non-recursively that `value` may be a JsonArray */\nexport function maybeJsonArray(value: unknown): value is JsonArray {\n return Array.isArray(value);\n}\n\n/** A type representing all valid JSON serializable values. */\nexport type JsonValue = JsonObject | JsonArray | JsonScalar;\n\n/** Asserts that `value` may be a JsonValue */\nexport function maybeJsonValue(value: unknown): value is JsonValue {\n return (\n typeof value !== 'undefined' &&\n (isJsonScalar(value) || maybeJsonObject(value) || maybeJsonArray(value))\n );\n}\n"],"names":[],"mappings":"AAmBO,SAAS,aAAa,KAAA,EAAqC;AAChE,EAAA,OACE,OAAO,UAAU,QAAA,IACjB,OAAO,UAAU,QAAA,IACjB,OAAO,KAAA,KAAU,SAAA,IACjB,KAAA,KAAU,IAAA;AAEd;AAQO,SAAS,gBAAgB,KAAA,EAAqC;AACnE,EAAA,OAAO,KAAA,EAAO,YAAY,IAAA,KAAS,QAAA;AACrC;AAMO,SAAS,eAAe,KAAA,EAAoC;AACjE,EAAA,OAAO,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC5B;AAMO,SAAS,eAAe,KAAA,EAAoC;AACjE,EAAA,OACE,OAAO,KAAA,KAAU,WAAA,KAChB,YAAA,CAAa,KAAK,KAAK,eAAA,CAAgB,KAAK,CAAA,IAAK,cAAA,CAAe,KAAK,CAAA,CAAA;AAE1E;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"json_node.cjs.js","sources":["../../../src/util/lib/json_node.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* eslint-disable no-console */\n/* eslint-disable default-case */\n/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n type JsonArray,\n type JsonObject,\n type JsonScalar,\n type JsonValue,\n maybeJsonArray,\n maybeJsonObject,\n} from './json';\nimport type { JsonNodeVisitor } from './json_node_visitor';\n\nconst refs = new Set<JsonObject | JsonArray>();\nfunction detectCircularReference(nodeValue: JsonObject | JsonArray): void {\n if (refs.has(nodeValue)) {\n throw new TypeError('Converting circular structure');\n } else {\n refs.add(nodeValue);\n }\n}\n\nexport type ObjectKeyMutatorFunction = (key: string | number) => string;\n\n/**\n * Options for configuring the JSON visitor.\n */\nexport interface JsonNodeVisitorOptions {\n /**\n * A list of regular expression matching the JSONPath (RFC 9535) of a key in the data structure.\n * Every time a key is found in the data structure, its JSONPath is tested for a match against the entries in the list.\n * If at least one match is found, then that key won't be processed by the `JsonNodeVisitorOptions#onVisitJsonObjectKey` callback.\n */\n skipList?: Array<RegExp>;\n\n /**\n * An optional flag to enable debug mode.\n * When set to true, each time a node is visited, its JSONPath will be logged.\n */\n debug?: boolean;\n\n /**\n * A function that can be used to process the object keys names.\n * The string returned by this function will be used to replace the name of the object key being visited.\n */\n onVisitJsonObjectKey?: ObjectKeyMutatorFunction;\n}\n\nclass Visitor implements JsonNodeVisitor {\n readonly #onVisitObjectKey?: ObjectKeyMutatorFunction;\n readonly #skipList: Array<RegExp>;\n readonly #isDebugEnabled: boolean;\n\n constructor(options?: JsonNodeVisitorOptions) {\n this.#onVisitObjectKey = options?.onVisitJsonObjectKey;\n this.#skipList = options?.skipList ?? [];\n this.#isDebugEnabled = options?.debug ?? false;\n }\n\n visitScalar(node: JsonNode<JsonScalar>): void {\n if (this.#isDebugEnabled) {\n console.log(node.jsonpath);\n }\n }\n\n visitArray(node: JsonNode<JsonArray>): void {\n if (this.#isDebugEnabled) {\n console.log(node.jsonpath);\n }\n\n node.children?.forEach(child => child.accept(this));\n }\n\n visitObject(node: JsonNode<JsonObject>): void {\n if (this.#isDebugEnabled) {\n console.log(node.jsonpath);\n }\n\n node.children?.forEach(child => {\n const newKey = this.#skipList.some(regex => regex.test(child.jsonpath))\n ? child.key\n : this.#onVisitObjectKey?.(child.key) ?? child.key;\n child.key = newKey;\n child.accept(this);\n });\n }\n}\n\n/** Represents a node in a tree structure where each node can be a scalar, array, or object. */\nexport class JsonNode<T extends JsonValue> {\n static readonly Visitor = Visitor;\n static #toJsonPathSegment(value: string | number): string {\n if (typeof value === 'number') {\n return `[${value}]`;\n }\n\n const regex = /(\\s|\\.)/;\n return regex.test(value) ? `['${value}']` : `.${value}`;\n }\n\n readonly #parent: JsonNode<JsonValue> | null;\n readonly #children: Array<JsonNode<JsonValue>> | null;\n readonly #kind: 'scalar' | 'array' | 'object';\n readonly #value: T;\n readonly #jsonpath: Array<string>;\n key: string | number;\n\n /**\n * Constructs a new Node instance.\n *\n * @param key - The key associated with this node, which can be a string or number.\n * @param value - The value associated with this node.\n * @param parent - The parent node of this node, if any.\n *\n * @throws {TypeError} If the key is not \"$\" and the parent node is not provided.\n */\n constructor(key: string | number, value: T, parent?: JsonNode<T>) {\n this.key = key;\n this.#value = value;\n this.#jsonpath = [];\n\n if (key === '$') {\n this.#parent = null;\n this.#jsonpath.push(key);\n } else {\n if (!parent) {\n throw new TypeError('Parent node is required');\n }\n\n this.#parent = parent;\n this.#jsonpath.push(\n ...this.#parent.jsonpath,\n `${JsonNode.#toJsonPathSegment(key)}`,\n );\n }\n\n switch (true) {\n case maybeJsonArray(value):\n detectCircularReference(value);\n this.#kind = 'array';\n this.#children = value.map(\n (jsonValue, idx) => new JsonNode(idx, jsonValue, this),\n );\n break;\n case maybeJsonObject(value):\n detectCircularReference(value);\n this.#kind = 'object';\n this.#children = [];\n for (const [k, jsonValue] of Object.entries(value)) {\n if (typeof jsonValue !== 'undefined') {\n this.#children.push(new JsonNode(k, jsonValue, this));\n }\n }\n break;\n default:\n this.#kind = 'scalar';\n this.#children = null;\n break;\n }\n\n if (this.parent === null) {\n refs.clear();\n }\n }\n\n get value(): T {\n return this.#value;\n }\n\n get kind(): 'scalar' | 'array' | 'object' {\n return this.#kind;\n }\n\n get parent(): JsonNode<JsonValue> | null {\n return this.#parent;\n }\n\n get children(): Array<JsonNode<JsonValue>> | null {\n return this.#children;\n }\n\n /**\n * Returns the JSONPath expression corresponding to this node's location in the data structure.\n *\n * @returns {string} The JSONPath expression.\n */\n get jsonpath(): string {\n return this.#jsonpath.join('');\n }\n\n /**\n * Accepts a visitor and calls the appropriate visit method based on the node's kind.\n *\n * @param visitor - The visitor instance that will process the node.\n *\n * The method will call one of the following visitor methods based on the node's kind:\n * - `visitScalar` if the node is a scalar.\n * - `visitArray` if the node is an array.\n * - `visitObject` if the node is an object.\n */\n accept(visitor: Visitor) {\n switch (this.#kind) {\n case 'scalar':\n visitor.visitScalar(this as JsonNode<JsonScalar>);\n break;\n case 'array':\n visitor.visitArray(this as JsonNode<JsonArray>);\n break;\n case 'object':\n visitor.visitObject(this as JsonNode<JsonObject>);\n break;\n }\n }\n\n /**\n * Converts the current instance to a JSON value.\n *\n * Depending on the type of the instance (`scalar`, `array`, or `object`),\n * this method will return the corresponding JSON representation.\n *\n * - If the instance is a scalar, it returns the scalar value.\n * - If the instance is an array, it returns an array of JSON values by\n * recursively calling `toJsonValue` on each child.\n * - If the instance is an object, it returns a JSON object by recursively\n * calling `toJsonValue` on each child and using their keys as the object's keys.\n *\n * @returns {JsonValue} The JSON representation of the current instance.\n */\n toJsonValue(): JsonValue {\n let obj: JsonValue = {};\n switch (this.#kind) {\n case 'scalar':\n obj = this.#value;\n break;\n case 'array':\n obj = this.#children!.map(child => child.toJsonValue());\n break;\n case 'object': {\n const tmpObj: JsonObject = {};\n for (const child of this.#children ?? []) {\n tmpObj[child.key] = child.toJsonValue();\n }\n obj = tmpObj;\n }\n }\n return obj;\n }\n}\n"],"names":["maybeJsonArray","maybeJsonObject"],"mappings":"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"}
1
+ {"version":3,"file":"json_node.cjs.js","sources":["../../../src/util/lib/json_node.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* eslint-disable no-console */\n/* eslint-disable default-case */\n/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n type JsonArray,\n type JsonObject,\n type JsonScalar,\n type JsonValue,\n maybeJsonArray,\n maybeJsonObject,\n} from './json';\nimport type { JsonNodeVisitor } from './json_node_visitor';\n\nconst refs = new Set<JsonObject | JsonArray>();\nfunction detectCircularReference(nodeValue: JsonObject | JsonArray): void {\n if (refs.has(nodeValue)) {\n throw new TypeError('Converting circular structure');\n } else {\n refs.add(nodeValue);\n }\n}\n\nexport type ObjectKeyMutatorFunction = (key: string | number) => string;\n\n/**\n * Options for configuring the JSON visitor.\n */\nexport interface JsonNodeVisitorOptions {\n /**\n * A list of regular expression matching the JSONPath (RFC 9535) of a key in the data structure.\n * Every time a key is found in the data structure, its JSONPath is tested for a match against the entries in the list.\n * If at least one match is found, then that key won't be processed by the `JsonNodeVisitorOptions#onVisitJsonObjectKey` callback.\n */\n skipList?: Array<RegExp>;\n\n /**\n * An optional flag to enable debug mode.\n * When set to true, each time a node is visited, its JSONPath will be logged.\n */\n debug?: boolean;\n\n /**\n * A function that can be used to process the object keys names.\n * The string returned by this function will be used to replace the name of the object key being visited.\n */\n onVisitJsonObjectKey?: ObjectKeyMutatorFunction;\n}\n\nclass Visitor implements JsonNodeVisitor {\n readonly #onVisitObjectKey?: ObjectKeyMutatorFunction;\n readonly #skipList: Array<RegExp>;\n readonly #isDebugEnabled: boolean;\n\n constructor(options?: JsonNodeVisitorOptions) {\n this.#onVisitObjectKey = options?.onVisitJsonObjectKey;\n this.#skipList = options?.skipList ?? [];\n this.#isDebugEnabled = options?.debug ?? false;\n }\n\n visitScalar(node: JsonNode<JsonScalar>): void {\n if (this.#isDebugEnabled) {\n console.log(node.jsonpath);\n }\n }\n\n visitArray(node: JsonNode<JsonArray>): void {\n if (this.#isDebugEnabled) {\n console.log(node.jsonpath);\n }\n\n node.children?.forEach(child => child.accept(this));\n }\n\n visitObject(node: JsonNode<JsonObject>): void {\n if (this.#isDebugEnabled) {\n console.log(node.jsonpath);\n }\n\n node.children?.forEach(child => {\n const newKey = this.#skipList.some(regex => regex.test(child.jsonpath))\n ? child.key\n : this.#onVisitObjectKey?.(child.key) ?? child.key;\n child.key = newKey;\n child.accept(this);\n });\n }\n}\n\n/** Represents a node in a tree structure where each node can be a scalar, array, or object. */\nexport class JsonNode<T extends JsonValue> {\n static readonly Visitor = Visitor;\n static #toJsonPathSegment(value: string | number): string {\n if (typeof value === 'number') {\n return `[${value}]`;\n }\n\n const regex = /(\\s|\\.)/;\n return regex.test(value) ? `['${value}']` : `.${value}`;\n }\n\n readonly #parent: JsonNode<JsonValue> | null;\n readonly #children: Array<JsonNode<JsonValue>> | null;\n readonly #kind: 'scalar' | 'array' | 'object';\n readonly #value: T;\n readonly #jsonpath: Array<string>;\n key: string | number;\n\n /**\n * Constructs a new Node instance.\n *\n * @param key - The key associated with this node, which can be a string or number.\n * @param value - The value associated with this node.\n * @param parent - The parent node of this node, if any.\n *\n * @throws {TypeError} If the key is not \"$\" and the parent node is not provided.\n */\n constructor(key: string | number, value: T, parent?: JsonNode<T>) {\n this.key = key;\n this.#value = value;\n this.#jsonpath = [];\n\n if (key === '$') {\n this.#parent = null;\n this.#jsonpath.push(key);\n } else {\n if (!parent) {\n throw new TypeError('Parent node is required');\n }\n\n this.#parent = parent;\n this.#jsonpath.push(\n ...this.#parent.jsonpath,\n `${JsonNode.#toJsonPathSegment(key)}`,\n );\n }\n\n switch (true) {\n case maybeJsonArray(value):\n detectCircularReference(value);\n this.#kind = 'array';\n this.#children = value.map(\n (jsonValue, idx) => new JsonNode(idx, jsonValue, this),\n );\n break;\n case maybeJsonObject(value):\n detectCircularReference(value);\n this.#kind = 'object';\n this.#children = [];\n for (const [k, jsonValue] of Object.entries(value)) {\n if (typeof jsonValue !== 'undefined') {\n this.#children.push(new JsonNode(k, jsonValue, this));\n }\n }\n break;\n default:\n this.#kind = 'scalar';\n this.#children = null;\n break;\n }\n\n if (this.parent === null) {\n refs.clear();\n }\n }\n\n get value(): T {\n return this.#value;\n }\n\n get kind(): 'scalar' | 'array' | 'object' {\n return this.#kind;\n }\n\n get parent(): JsonNode<JsonValue> | null {\n return this.#parent;\n }\n\n get children(): Array<JsonNode<JsonValue>> | null {\n return this.#children;\n }\n\n /**\n * Returns the JSONPath expression corresponding to this node's location in the data structure.\n *\n * @returns {string} The JSONPath expression.\n */\n get jsonpath(): string {\n return this.#jsonpath.join('');\n }\n\n /**\n * Accepts a visitor and calls the appropriate visit method based on the node's kind.\n *\n * @param visitor - The visitor instance that will process the node.\n *\n * The method will call one of the following visitor methods based on the node's kind:\n * - `visitScalar` if the node is a scalar.\n * - `visitArray` if the node is an array.\n * - `visitObject` if the node is an object.\n */\n accept(visitor: Visitor) {\n switch (this.#kind) {\n case 'scalar':\n visitor.visitScalar(this as JsonNode<JsonScalar>);\n break;\n case 'array':\n visitor.visitArray(this as JsonNode<JsonArray>);\n break;\n case 'object':\n visitor.visitObject(this as JsonNode<JsonObject>);\n break;\n }\n }\n\n /**\n * Converts the current instance to a JSON value.\n *\n * Depending on the type of the instance (`scalar`, `array`, or `object`),\n * this method will return the corresponding JSON representation.\n *\n * - If the instance is a scalar, it returns the scalar value.\n * - If the instance is an array, it returns an array of JSON values by\n * recursively calling `toJsonValue` on each child.\n * - If the instance is an object, it returns a JSON object by recursively\n * calling `toJsonValue` on each child and using their keys as the object's keys.\n *\n * @returns {JsonValue} The JSON representation of the current instance.\n */\n toJsonValue(): JsonValue {\n let obj: JsonValue = {};\n switch (this.#kind) {\n case 'scalar':\n obj = this.#value;\n break;\n case 'array':\n obj = this.#children!.map(child => child.toJsonValue());\n break;\n case 'object': {\n const tmpObj: JsonObject = {};\n for (const child of this.#children ?? []) {\n tmpObj[child.key] = child.toJsonValue();\n }\n obj = tmpObj;\n }\n }\n return obj;\n }\n}\n"],"names":["maybeJsonArray","maybeJsonObject"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"json_node.esm.js","sources":["../../../src/util/lib/json_node.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* eslint-disable no-console */\n/* eslint-disable default-case */\n/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n type JsonArray,\n type JsonObject,\n type JsonScalar,\n type JsonValue,\n maybeJsonArray,\n maybeJsonObject,\n} from './json';\nimport type { JsonNodeVisitor } from './json_node_visitor';\n\nconst refs = new Set<JsonObject | JsonArray>();\nfunction detectCircularReference(nodeValue: JsonObject | JsonArray): void {\n if (refs.has(nodeValue)) {\n throw new TypeError('Converting circular structure');\n } else {\n refs.add(nodeValue);\n }\n}\n\nexport type ObjectKeyMutatorFunction = (key: string | number) => string;\n\n/**\n * Options for configuring the JSON visitor.\n */\nexport interface JsonNodeVisitorOptions {\n /**\n * A list of regular expression matching the JSONPath (RFC 9535) of a key in the data structure.\n * Every time a key is found in the data structure, its JSONPath is tested for a match against the entries in the list.\n * If at least one match is found, then that key won't be processed by the `JsonNodeVisitorOptions#onVisitJsonObjectKey` callback.\n */\n skipList?: Array<RegExp>;\n\n /**\n * An optional flag to enable debug mode.\n * When set to true, each time a node is visited, its JSONPath will be logged.\n */\n debug?: boolean;\n\n /**\n * A function that can be used to process the object keys names.\n * The string returned by this function will be used to replace the name of the object key being visited.\n */\n onVisitJsonObjectKey?: ObjectKeyMutatorFunction;\n}\n\nclass Visitor implements JsonNodeVisitor {\n readonly #onVisitObjectKey?: ObjectKeyMutatorFunction;\n readonly #skipList: Array<RegExp>;\n readonly #isDebugEnabled: boolean;\n\n constructor(options?: JsonNodeVisitorOptions) {\n this.#onVisitObjectKey = options?.onVisitJsonObjectKey;\n this.#skipList = options?.skipList ?? [];\n this.#isDebugEnabled = options?.debug ?? false;\n }\n\n visitScalar(node: JsonNode<JsonScalar>): void {\n if (this.#isDebugEnabled) {\n console.log(node.jsonpath);\n }\n }\n\n visitArray(node: JsonNode<JsonArray>): void {\n if (this.#isDebugEnabled) {\n console.log(node.jsonpath);\n }\n\n node.children?.forEach(child => child.accept(this));\n }\n\n visitObject(node: JsonNode<JsonObject>): void {\n if (this.#isDebugEnabled) {\n console.log(node.jsonpath);\n }\n\n node.children?.forEach(child => {\n const newKey = this.#skipList.some(regex => regex.test(child.jsonpath))\n ? child.key\n : this.#onVisitObjectKey?.(child.key) ?? child.key;\n child.key = newKey;\n child.accept(this);\n });\n }\n}\n\n/** Represents a node in a tree structure where each node can be a scalar, array, or object. */\nexport class JsonNode<T extends JsonValue> {\n static readonly Visitor = Visitor;\n static #toJsonPathSegment(value: string | number): string {\n if (typeof value === 'number') {\n return `[${value}]`;\n }\n\n const regex = /(\\s|\\.)/;\n return regex.test(value) ? `['${value}']` : `.${value}`;\n }\n\n readonly #parent: JsonNode<JsonValue> | null;\n readonly #children: Array<JsonNode<JsonValue>> | null;\n readonly #kind: 'scalar' | 'array' | 'object';\n readonly #value: T;\n readonly #jsonpath: Array<string>;\n key: string | number;\n\n /**\n * Constructs a new Node instance.\n *\n * @param key - The key associated with this node, which can be a string or number.\n * @param value - The value associated with this node.\n * @param parent - The parent node of this node, if any.\n *\n * @throws {TypeError} If the key is not \"$\" and the parent node is not provided.\n */\n constructor(key: string | number, value: T, parent?: JsonNode<T>) {\n this.key = key;\n this.#value = value;\n this.#jsonpath = [];\n\n if (key === '$') {\n this.#parent = null;\n this.#jsonpath.push(key);\n } else {\n if (!parent) {\n throw new TypeError('Parent node is required');\n }\n\n this.#parent = parent;\n this.#jsonpath.push(\n ...this.#parent.jsonpath,\n `${JsonNode.#toJsonPathSegment(key)}`,\n );\n }\n\n switch (true) {\n case maybeJsonArray(value):\n detectCircularReference(value);\n this.#kind = 'array';\n this.#children = value.map(\n (jsonValue, idx) => new JsonNode(idx, jsonValue, this),\n );\n break;\n case maybeJsonObject(value):\n detectCircularReference(value);\n this.#kind = 'object';\n this.#children = [];\n for (const [k, jsonValue] of Object.entries(value)) {\n if (typeof jsonValue !== 'undefined') {\n this.#children.push(new JsonNode(k, jsonValue, this));\n }\n }\n break;\n default:\n this.#kind = 'scalar';\n this.#children = null;\n break;\n }\n\n if (this.parent === null) {\n refs.clear();\n }\n }\n\n get value(): T {\n return this.#value;\n }\n\n get kind(): 'scalar' | 'array' | 'object' {\n return this.#kind;\n }\n\n get parent(): JsonNode<JsonValue> | null {\n return this.#parent;\n }\n\n get children(): Array<JsonNode<JsonValue>> | null {\n return this.#children;\n }\n\n /**\n * Returns the JSONPath expression corresponding to this node's location in the data structure.\n *\n * @returns {string} The JSONPath expression.\n */\n get jsonpath(): string {\n return this.#jsonpath.join('');\n }\n\n /**\n * Accepts a visitor and calls the appropriate visit method based on the node's kind.\n *\n * @param visitor - The visitor instance that will process the node.\n *\n * The method will call one of the following visitor methods based on the node's kind:\n * - `visitScalar` if the node is a scalar.\n * - `visitArray` if the node is an array.\n * - `visitObject` if the node is an object.\n */\n accept(visitor: Visitor) {\n switch (this.#kind) {\n case 'scalar':\n visitor.visitScalar(this as JsonNode<JsonScalar>);\n break;\n case 'array':\n visitor.visitArray(this as JsonNode<JsonArray>);\n break;\n case 'object':\n visitor.visitObject(this as JsonNode<JsonObject>);\n break;\n }\n }\n\n /**\n * Converts the current instance to a JSON value.\n *\n * Depending on the type of the instance (`scalar`, `array`, or `object`),\n * this method will return the corresponding JSON representation.\n *\n * - If the instance is a scalar, it returns the scalar value.\n * - If the instance is an array, it returns an array of JSON values by\n * recursively calling `toJsonValue` on each child.\n * - If the instance is an object, it returns a JSON object by recursively\n * calling `toJsonValue` on each child and using their keys as the object's keys.\n *\n * @returns {JsonValue} The JSON representation of the current instance.\n */\n toJsonValue(): JsonValue {\n let obj: JsonValue = {};\n switch (this.#kind) {\n case 'scalar':\n obj = this.#value;\n break;\n case 'array':\n obj = this.#children!.map(child => child.toJsonValue());\n break;\n case 'object': {\n const tmpObj: JsonObject = {};\n for (const child of this.#children ?? []) {\n tmpObj[child.key] = child.toJsonValue();\n }\n obj = tmpObj;\n }\n }\n return obj;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"json_node.esm.js","sources":["../../../src/util/lib/json_node.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* eslint-disable no-console */\n/* eslint-disable default-case */\n/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n type JsonArray,\n type JsonObject,\n type JsonScalar,\n type JsonValue,\n maybeJsonArray,\n maybeJsonObject,\n} from './json';\nimport type { JsonNodeVisitor } from './json_node_visitor';\n\nconst refs = new Set<JsonObject | JsonArray>();\nfunction detectCircularReference(nodeValue: JsonObject | JsonArray): void {\n if (refs.has(nodeValue)) {\n throw new TypeError('Converting circular structure');\n } else {\n refs.add(nodeValue);\n }\n}\n\nexport type ObjectKeyMutatorFunction = (key: string | number) => string;\n\n/**\n * Options for configuring the JSON visitor.\n */\nexport interface JsonNodeVisitorOptions {\n /**\n * A list of regular expression matching the JSONPath (RFC 9535) of a key in the data structure.\n * Every time a key is found in the data structure, its JSONPath is tested for a match against the entries in the list.\n * If at least one match is found, then that key won't be processed by the `JsonNodeVisitorOptions#onVisitJsonObjectKey` callback.\n */\n skipList?: Array<RegExp>;\n\n /**\n * An optional flag to enable debug mode.\n * When set to true, each time a node is visited, its JSONPath will be logged.\n */\n debug?: boolean;\n\n /**\n * A function that can be used to process the object keys names.\n * The string returned by this function will be used to replace the name of the object key being visited.\n */\n onVisitJsonObjectKey?: ObjectKeyMutatorFunction;\n}\n\nclass Visitor implements JsonNodeVisitor {\n readonly #onVisitObjectKey?: ObjectKeyMutatorFunction;\n readonly #skipList: Array<RegExp>;\n readonly #isDebugEnabled: boolean;\n\n constructor(options?: JsonNodeVisitorOptions) {\n this.#onVisitObjectKey = options?.onVisitJsonObjectKey;\n this.#skipList = options?.skipList ?? [];\n this.#isDebugEnabled = options?.debug ?? false;\n }\n\n visitScalar(node: JsonNode<JsonScalar>): void {\n if (this.#isDebugEnabled) {\n console.log(node.jsonpath);\n }\n }\n\n visitArray(node: JsonNode<JsonArray>): void {\n if (this.#isDebugEnabled) {\n console.log(node.jsonpath);\n }\n\n node.children?.forEach(child => child.accept(this));\n }\n\n visitObject(node: JsonNode<JsonObject>): void {\n if (this.#isDebugEnabled) {\n console.log(node.jsonpath);\n }\n\n node.children?.forEach(child => {\n const newKey = this.#skipList.some(regex => regex.test(child.jsonpath))\n ? child.key\n : this.#onVisitObjectKey?.(child.key) ?? child.key;\n child.key = newKey;\n child.accept(this);\n });\n }\n}\n\n/** Represents a node in a tree structure where each node can be a scalar, array, or object. */\nexport class JsonNode<T extends JsonValue> {\n static readonly Visitor = Visitor;\n static #toJsonPathSegment(value: string | number): string {\n if (typeof value === 'number') {\n return `[${value}]`;\n }\n\n const regex = /(\\s|\\.)/;\n return regex.test(value) ? `['${value}']` : `.${value}`;\n }\n\n readonly #parent: JsonNode<JsonValue> | null;\n readonly #children: Array<JsonNode<JsonValue>> | null;\n readonly #kind: 'scalar' | 'array' | 'object';\n readonly #value: T;\n readonly #jsonpath: Array<string>;\n key: string | number;\n\n /**\n * Constructs a new Node instance.\n *\n * @param key - The key associated with this node, which can be a string or number.\n * @param value - The value associated with this node.\n * @param parent - The parent node of this node, if any.\n *\n * @throws {TypeError} If the key is not \"$\" and the parent node is not provided.\n */\n constructor(key: string | number, value: T, parent?: JsonNode<T>) {\n this.key = key;\n this.#value = value;\n this.#jsonpath = [];\n\n if (key === '$') {\n this.#parent = null;\n this.#jsonpath.push(key);\n } else {\n if (!parent) {\n throw new TypeError('Parent node is required');\n }\n\n this.#parent = parent;\n this.#jsonpath.push(\n ...this.#parent.jsonpath,\n `${JsonNode.#toJsonPathSegment(key)}`,\n );\n }\n\n switch (true) {\n case maybeJsonArray(value):\n detectCircularReference(value);\n this.#kind = 'array';\n this.#children = value.map(\n (jsonValue, idx) => new JsonNode(idx, jsonValue, this),\n );\n break;\n case maybeJsonObject(value):\n detectCircularReference(value);\n this.#kind = 'object';\n this.#children = [];\n for (const [k, jsonValue] of Object.entries(value)) {\n if (typeof jsonValue !== 'undefined') {\n this.#children.push(new JsonNode(k, jsonValue, this));\n }\n }\n break;\n default:\n this.#kind = 'scalar';\n this.#children = null;\n break;\n }\n\n if (this.parent === null) {\n refs.clear();\n }\n }\n\n get value(): T {\n return this.#value;\n }\n\n get kind(): 'scalar' | 'array' | 'object' {\n return this.#kind;\n }\n\n get parent(): JsonNode<JsonValue> | null {\n return this.#parent;\n }\n\n get children(): Array<JsonNode<JsonValue>> | null {\n return this.#children;\n }\n\n /**\n * Returns the JSONPath expression corresponding to this node's location in the data structure.\n *\n * @returns {string} The JSONPath expression.\n */\n get jsonpath(): string {\n return this.#jsonpath.join('');\n }\n\n /**\n * Accepts a visitor and calls the appropriate visit method based on the node's kind.\n *\n * @param visitor - The visitor instance that will process the node.\n *\n * The method will call one of the following visitor methods based on the node's kind:\n * - `visitScalar` if the node is a scalar.\n * - `visitArray` if the node is an array.\n * - `visitObject` if the node is an object.\n */\n accept(visitor: Visitor) {\n switch (this.#kind) {\n case 'scalar':\n visitor.visitScalar(this as JsonNode<JsonScalar>);\n break;\n case 'array':\n visitor.visitArray(this as JsonNode<JsonArray>);\n break;\n case 'object':\n visitor.visitObject(this as JsonNode<JsonObject>);\n break;\n }\n }\n\n /**\n * Converts the current instance to a JSON value.\n *\n * Depending on the type of the instance (`scalar`, `array`, or `object`),\n * this method will return the corresponding JSON representation.\n *\n * - If the instance is a scalar, it returns the scalar value.\n * - If the instance is an array, it returns an array of JSON values by\n * recursively calling `toJsonValue` on each child.\n * - If the instance is an object, it returns a JSON object by recursively\n * calling `toJsonValue` on each child and using their keys as the object's keys.\n *\n * @returns {JsonValue} The JSON representation of the current instance.\n */\n toJsonValue(): JsonValue {\n let obj: JsonValue = {};\n switch (this.#kind) {\n case 'scalar':\n obj = this.#value;\n break;\n case 'array':\n obj = this.#children!.map(child => child.toJsonValue());\n break;\n case 'object': {\n const tmpObj: JsonObject = {};\n for (const child of this.#children ?? []) {\n tmpObj[child.key] = child.toJsonValue();\n }\n obj = tmpObj;\n }\n }\n return obj;\n }\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@red-hat-developer-hub/plugin-cost-management-common",
3
3
  "description": "Common functionalities for the cost-management plugin",
4
- "version": "2.0.1",
4
+ "version": "2.1.0",
5
5
  "backstage": {
6
6
  "pluginId": "cost-management",
7
7
  "pluginPackages": [
@@ -13,15 +13,15 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "@backstage-community/plugin-rbac-common": "^1.12.2",
16
- "@backstage/core-plugin-api": "^1.10.3",
17
- "@backstage/plugin-permission-common": "^0.8.4",
16
+ "@backstage/core-plugin-api": "^1.12.4",
17
+ "@backstage/plugin-permission-common": "^0.9.7",
18
18
  "cross-fetch": "^4.0.0",
19
19
  "lodash": "^4.17.21",
20
20
  "uri-template": "^2.0.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@backstage/cli": "^0.29.4",
24
- "@backstage/types": "^1.2.1",
23
+ "@backstage/cli": "^0.36.0",
24
+ "@backstage/types": "^1.2.2",
25
25
  "@testing-library/jest-dom": "^6.0.0",
26
26
  "@types/lodash": "^4.17.5",
27
27
  "msw": "^2.3.4",
@@ -69,9 +69,6 @@
69
69
  },
70
70
  "typesVersions": {
71
71
  "*": {
72
- "index": [
73
- "dist/index.d.ts"
74
- ],
75
72
  "models": [
76
73
  "dist/models.d.ts"
77
74
  ],
@@ -86,6 +83,9 @@
86
83
  ],
87
84
  "permissions": [
88
85
  "dist/permissions.d.ts"
86
+ ],
87
+ "package.json": [
88
+ "package.json"
89
89
  ]
90
90
  }
91
91
  },