@axis-backstage/plugin-jira-dashboard-backend 6.1.0 → 6.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @axis-backstage/plugin-jira-dashboard-backend
2
2
 
3
+ ## 6.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - a1d5a9a: Refactored the Jira Dashboard backend to batch project keys into a single JQL query (getIssuesByFilter) and to run independent async operations concurrently with Promise.all / Promise.allSettled, reducing latency when multiple projects or filters are fetched.
8
+
9
+ ## 6.1.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 199bd49: Fix critical security vulnerabilities by upgrading Backstage dependencies:
14
+
15
+ **Security Fixes:**
16
+
17
+ - Fixed CVE-2025-8101 (High Severity) in linkifyjs/linkify-react by upgrading @backstage/core-components from ^0.18.4 to ^0.18.6
18
+ - Fixed CVE-2026-24046 (High Severity) - UNIX Symbolic Link Following in @backstage/backend-plugin-api by upgrading from ^1.6.0 to ^1.6.2
19
+ - Fixed CVE-2026-24047 (High Severity) - Symlink Attack in @backstage/backend-defaults by upgrading from ^0.14.0 to ^0.15.1
20
+ - Fixed SNYK-JS-QS-14724253 (High Severity) - Allocation of Resources Without Limits or Throttling in qs by adding resolution to ^6.14.1
21
+
22
+ **Additional Package Upgrades:**
23
+ Upgraded packages to versions that depend on patched Backstage core packages:
24
+
25
+ - @backstage/plugin-mcp-actions-backend: ^0.1.6 → ^0.1.8
26
+ - @backstage/plugin-search-backend: ^2.0.9 → ^2.0.11
27
+ - @backstage/plugin-techdocs-backend: ^2.1.3 → ^2.1.4
28
+ - @backstage/backend-test-utils: ^1.10.2 → ^1.10.4 (in jira-dashboard-backend and readme-backend)
29
+
30
+ **Code Improvements:**
31
+
32
+ - Removed redundant @backstage/backend-defaults imports from production code paths in backend plugins (jira-dashboard-backend, readme-backend, statuspage-backend)
33
+
3
34
  ## 6.1.0
4
35
 
5
36
  ### Minor Changes
package/dist/api.cjs.js CHANGED
@@ -63,28 +63,29 @@ const getQueryUrl = (instance, jql) => {
63
63
  return baseUrlWithEndpoint;
64
64
  };
65
65
  const getIssuesByFilter = async (projects, components, query) => {
66
- const issues = [];
67
- for (const project of projects) {
68
- const { projectKey, instance } = project;
69
- const jql = queries.jqlQueryBuilder({ project: [projectKey], components, query });
70
- const queryUrl = getQueryUrl(instance, jql);
71
- const response = await callApi(instance, queryUrl, {
72
- method: "GET",
73
- headers: {
74
- Accept: "application/json"
75
- }
76
- }).then((resp) => resp.json()).catch(() => null);
77
- if (response?.errorMessages) {
78
- throw Error(
79
- `JQL returned Error: JQL - ${jql} with error: ${response?.errorMessages?.[0]}`
80
- );
81
- }
82
- if (response?.issues) {
83
- lib.replaceIssuesApiUrl(project.instance, response.issues);
84
- issues.push(...response.issues);
66
+ if (projects.length === 0) {
67
+ return [];
68
+ }
69
+ const { instance } = projects[0];
70
+ const projectKeys = projects.map((p) => p.projectKey);
71
+ const jql = queries.jqlQueryBuilder({ project: projectKeys, components, query });
72
+ const queryUrl = getQueryUrl(instance, jql);
73
+ const response = await callApi(instance, queryUrl, {
74
+ method: "GET",
75
+ headers: {
76
+ Accept: "application/json"
85
77
  }
78
+ }).then((resp) => resp.json()).catch(() => null);
79
+ if (response?.errorMessages) {
80
+ throw Error(
81
+ `JQL returned Error: JQL - ${jql} with error: ${response?.errorMessages?.[0]}`
82
+ );
83
+ }
84
+ if (response?.issues) {
85
+ lib.replaceIssuesApiUrl(instance, response.issues);
86
+ return response.issues;
86
87
  }
87
- return issues;
88
+ return [];
88
89
  };
89
90
  const searchJira = async (instance, jqlQuery, options) => {
90
91
  const queryUrl = getQueryUrl(instance);
@@ -1 +1 @@
1
- {"version":3,"file":"api.cjs.js","sources":["../src/api.ts"],"sourcesContent":["import fetch, { RequestInit } from 'node-fetch';\nimport {\n Filter,\n Issue,\n Project,\n JiraQueryResults,\n} from '@axis-backstage/plugin-jira-dashboard-common';\n\nimport type { ConfigInstance } from './config';\nimport { jqlQueryBuilder } from './queries';\nimport type { JiraProject } from './lib';\nimport { getApiUrl, replaceProjectApiUrl, replaceIssuesApiUrl } from './lib';\nimport { ResponseError } from '@backstage/errors';\n\nexport const getProjectInfo = async (\n project: JiraProject,\n): Promise<Project> => {\n const { projectKey, instance } = project;\n const response = await callApi(\n instance,\n `${getApiUrl(instance)}project/${projectKey}`,\n {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n },\n );\n if (response.status !== 200) {\n throw Error(\n `Request failed with status code ${response.status}: ${response.statusText}`,\n );\n }\n\n const projectResponse = await response.json();\n replaceProjectApiUrl(project.instance, projectResponse);\n return projectResponse;\n};\n\nexport const getFilterById = async (\n id: string,\n instance: ConfigInstance,\n): Promise<Filter> => {\n const response = await callApi(\n instance,\n `${getApiUrl(instance)}filter/${id}`,\n {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n },\n );\n if (response.status !== 200) {\n throw Error(`${response.status}`);\n }\n const jsonResponse = await response.json();\n return { name: jsonResponse.name, query: jsonResponse.jql } as Filter;\n};\n\nexport const getQueryUrl = (instance: ConfigInstance, jql?: string): string => {\n const baseUrl = getApiUrl(instance);\n\n if (instance.useApiV3) {\n const baseUrlWithEndpoint = `${baseUrl}search/jql`;\n if (jql) {\n return `${baseUrlWithEndpoint}?jql=${jql}&fields=*all`;\n }\n return baseUrlWithEndpoint;\n }\n\n const baseUrlWithEndpoint = `${baseUrl}search`;\n if (jql) {\n return `${baseUrlWithEndpoint}?jql=${jql}`;\n }\n return baseUrlWithEndpoint;\n};\n\nexport const getIssuesByFilter = async (\n projects: JiraProject[],\n components: string[],\n query: string,\n): Promise<Issue[]> => {\n const issues: Issue[] = [];\n for (const project of projects) {\n const { projectKey, instance } = project;\n const jql = jqlQueryBuilder({ project: [projectKey], components, query });\n const queryUrl = getQueryUrl(instance, jql);\n const response = await callApi(instance, queryUrl, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n })\n .then(resp => resp.json())\n .catch(() => null);\n if (response?.errorMessages) {\n throw Error(\n `JQL returned Error: JQL - ${jql} with error: ${response?.errorMessages?.[0]}`,\n );\n }\n if (response?.issues) {\n replaceIssuesApiUrl(project.instance, response.issues);\n issues.push(...response.issues);\n }\n }\n\n return issues;\n};\n\n/**\n * Options available for the Jira JQL query.\n *\n * @public\n */\nexport type SearchOptions = {\n expand?: string[];\n fields?: string[];\n fieldsByKey?: boolean;\n properties?: string[];\n startAt?: number;\n maxResults?: number;\n validateQuery?: string;\n};\n\n/**\n * Asynchronously searches for Jira issues using JQL.\n *\n * For more information about the available options, see the API documentation at:\n * https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issue-search/#api-rest-api-2-search-post\n *\n * @param config - A Backstage config\n * @param jqlQuery - A string containing the jql query.\n * @param options - Query options that will be passed on to the POST request.\n * @public\n */\nexport const searchJira = async (\n instance: ConfigInstance,\n jqlQuery: string,\n options: SearchOptions,\n): Promise<JiraQueryResults> => {\n const queryUrl = getQueryUrl(instance);\n const requestBody = { jql: jqlQuery, ...options };\n\n const response = await callApi(instance, queryUrl, {\n method: 'POST',\n body: JSON.stringify(requestBody),\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n });\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n const jsonResponse = (await response.json()) as JiraQueryResults;\n replaceIssuesApiUrl(instance, jsonResponse.issues);\n return jsonResponse;\n};\n\nexport const getIssuesByComponent = async (\n projects: JiraProject[],\n componentKeys: string,\n query?: string,\n): Promise<Issue[]> => {\n // Return an empty array if no projects are provided\n if (projects.length === 0) {\n return [];\n }\n\n const projectKeys = projects.map(project => project.projectKey);\n const components = componentKeys\n .split(',')\n .map(component => component.trim());\n\n const jql = jqlQueryBuilder({\n project: projectKeys,\n components,\n query,\n });\n\n const { instance } = projects[0];\n\n try {\n const queryUrl = getQueryUrl(instance, jql);\n const response = await callApi(instance, queryUrl, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n }).then(resp => resp.json());\n\n if (!response.issues || response.issues.length === 0) {\n return [];\n }\n\n replaceIssuesApiUrl(instance, response.issues);\n return response.issues;\n } catch (error: any) {\n if (error.message.includes(\"does not exist for the field 'project'\")) {\n return [];\n }\n throw error;\n }\n};\nexport async function getProjectAvatar(url: string, instance: ConfigInstance) {\n return callApi(instance, url);\n}\n\n/**\n * Get a single Jira issue by its key or ID.\n *\n * @param issueKey - The issue key (e.g., \"PROJ-123\") or ID\n * @param instance - The Jira instance configuration\n * @returns The Jira issue\n * @public\n */\nexport const getIssueByKey = async (\n issueKey: string,\n instance: ConfigInstance,\n): Promise<Issue> => {\n const response = await callApi(\n instance,\n `${getApiUrl(instance)}issue/${issueKey}?fields=summary,description`,\n {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n },\n );\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n const issue = (await response.json()) as Issue;\n return issue;\n};\n\n/**\n * Call the Jira API using fetch.\n *\n * This function injects the auth token and custom headers.\n *\n * @public\n */\nexport async function callApi(\n instance: ConfigInstance,\n url: string,\n init?: RequestInit,\n) {\n const requestInit = init ?? { method: 'GET' };\n\n // Inject custom headers from config, Authorization token and headers from the\n // request\n requestInit.headers = {\n ...instance.headers,\n Authorization: instance.token,\n ...requestInit.headers,\n };\n return fetch(url, requestInit);\n}\n"],"names":["getApiUrl","replaceProjectApiUrl","baseUrlWithEndpoint","jqlQueryBuilder","replaceIssuesApiUrl","ResponseError","fetch"],"mappings":";;;;;;;;;;;AAca,MAAA,cAAA,GAAiB,OAC5B,OACqB,KAAA;AACrB,EAAM,MAAA,EAAE,UAAY,EAAA,QAAA,EAAa,GAAA,OAAA;AACjC,EAAA,MAAM,WAAW,MAAM,OAAA;AAAA,IACrB,QAAA;AAAA,IACA,CAAG,EAAAA,aAAA,CAAU,QAAQ,CAAC,WAAW,UAAU,CAAA,CAAA;AAAA,IAC3C;AAAA,MACE,MAAQ,EAAA,KAAA;AAAA,MACR,OAAS,EAAA;AAAA,QACP,MAAQ,EAAA;AAAA;AACV;AACF,GACF;AACA,EAAI,IAAA,QAAA,CAAS,WAAW,GAAK,EAAA;AAC3B,IAAM,MAAA,KAAA;AAAA,MACJ,CAAmC,gCAAA,EAAA,QAAA,CAAS,MAAM,CAAA,EAAA,EAAK,SAAS,UAAU,CAAA;AAAA,KAC5E;AAAA;AAGF,EAAM,MAAA,eAAA,GAAkB,MAAM,QAAA,CAAS,IAAK,EAAA;AAC5C,EAAqBC,wBAAA,CAAA,OAAA,CAAQ,UAAU,eAAe,CAAA;AACtD,EAAO,OAAA,eAAA;AACT;AAEa,MAAA,aAAA,GAAgB,OAC3B,EAAA,EACA,QACoB,KAAA;AACpB,EAAA,MAAM,WAAW,MAAM,OAAA;AAAA,IACrB,QAAA;AAAA,IACA,CAAG,EAAAD,aAAA,CAAU,QAAQ,CAAC,UAAU,EAAE,CAAA,CAAA;AAAA,IAClC;AAAA,MACE,MAAQ,EAAA,KAAA;AAAA,MACR,OAAS,EAAA;AAAA,QACP,MAAQ,EAAA;AAAA;AACV;AACF,GACF;AACA,EAAI,IAAA,QAAA,CAAS,WAAW,GAAK,EAAA;AAC3B,IAAA,MAAM,KAAM,CAAA,CAAA,EAAG,QAAS,CAAA,MAAM,CAAE,CAAA,CAAA;AAAA;AAElC,EAAM,MAAA,YAAA,GAAe,MAAM,QAAA,CAAS,IAAK,EAAA;AACzC,EAAA,OAAO,EAAE,IAAM,EAAA,YAAA,CAAa,IAAM,EAAA,KAAA,EAAO,aAAa,GAAI,EAAA;AAC5D;AAEa,MAAA,WAAA,GAAc,CAAC,QAAA,EAA0B,GAAyB,KAAA;AAC7E,EAAM,MAAA,OAAA,GAAUA,cAAU,QAAQ,CAAA;AAElC,EAAA,IAAI,SAAS,QAAU,EAAA;AACrB,IAAME,MAAAA,oBAAAA,GAAsB,GAAG,OAAO,CAAA,UAAA,CAAA;AACtC,IAAA,IAAI,GAAK,EAAA;AACP,MAAO,OAAA,CAAA,EAAGA,oBAAmB,CAAA,KAAA,EAAQ,GAAG,CAAA,YAAA,CAAA;AAAA;AAE1C,IAAOA,OAAAA,oBAAAA;AAAA;AAGT,EAAM,MAAA,mBAAA,GAAsB,GAAG,OAAO,CAAA,MAAA,CAAA;AACtC,EAAA,IAAI,GAAK,EAAA;AACP,IAAO,OAAA,CAAA,EAAG,mBAAmB,CAAA,KAAA,EAAQ,GAAG,CAAA,CAAA;AAAA;AAE1C,EAAO,OAAA,mBAAA;AACT;AAEO,MAAM,iBAAoB,GAAA,OAC/B,QACA,EAAA,UAAA,EACA,KACqB,KAAA;AACrB,EAAA,MAAM,SAAkB,EAAC;AACzB,EAAA,KAAA,MAAW,WAAW,QAAU,EAAA;AAC9B,IAAM,MAAA,EAAE,UAAY,EAAA,QAAA,EAAa,GAAA,OAAA;AACjC,IAAM,MAAA,GAAA,GAAMC,wBAAgB,EAAE,OAAA,EAAS,CAAC,UAAU,CAAA,EAAG,UAAY,EAAA,KAAA,EAAO,CAAA;AACxE,IAAM,MAAA,QAAA,GAAW,WAAY,CAAA,QAAA,EAAU,GAAG,CAAA;AAC1C,IAAA,MAAM,QAAW,GAAA,MAAM,OAAQ,CAAA,QAAA,EAAU,QAAU,EAAA;AAAA,MACjD,MAAQ,EAAA,KAAA;AAAA,MACR,OAAS,EAAA;AAAA,QACP,MAAQ,EAAA;AAAA;AACV,KACD,CACE,CAAA,IAAA,CAAK,CAAQ,IAAA,KAAA,IAAA,CAAK,MAAM,CAAA,CACxB,KAAM,CAAA,MAAM,IAAI,CAAA;AACnB,IAAA,IAAI,UAAU,aAAe,EAAA;AAC3B,MAAM,MAAA,KAAA;AAAA,QACJ,8BAA8B,GAAG,CAAA,aAAA,EAAgB,QAAU,EAAA,aAAA,GAAgB,CAAC,CAAC,CAAA;AAAA,OAC/E;AAAA;AAEF,IAAA,IAAI,UAAU,MAAQ,EAAA;AACpB,MAAoBC,uBAAA,CAAA,OAAA,CAAQ,QAAU,EAAA,QAAA,CAAS,MAAM,CAAA;AACrD,MAAO,MAAA,CAAA,IAAA,CAAK,GAAG,QAAA,CAAS,MAAM,CAAA;AAAA;AAChC;AAGF,EAAO,OAAA,MAAA;AACT;AA4BO,MAAM,UAAa,GAAA,OACxB,QACA,EAAA,QAAA,EACA,OAC8B,KAAA;AAC9B,EAAM,MAAA,QAAA,GAAW,YAAY,QAAQ,CAAA;AACrC,EAAA,MAAM,WAAc,GAAA,EAAE,GAAK,EAAA,QAAA,EAAU,GAAG,OAAQ,EAAA;AAEhD,EAAA,MAAM,QAAW,GAAA,MAAM,OAAQ,CAAA,QAAA,EAAU,QAAU,EAAA;AAAA,IACjD,MAAQ,EAAA,MAAA;AAAA,IACR,IAAA,EAAM,IAAK,CAAA,SAAA,CAAU,WAAW,CAAA;AAAA,IAChC,OAAS,EAAA;AAAA,MACP,MAAQ,EAAA,kBAAA;AAAA,MACR,cAAgB,EAAA;AAAA;AAClB,GACD,CAAA;AACD,EAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,IAAM,MAAA,MAAMC,oBAAc,CAAA,YAAA,CAAa,QAAQ,CAAA;AAAA;AAEjD,EAAM,MAAA,YAAA,GAAgB,MAAM,QAAA,CAAS,IAAK,EAAA;AAC1C,EAAoBD,uBAAA,CAAA,QAAA,EAAU,aAAa,MAAM,CAAA;AACjD,EAAO,OAAA,YAAA;AACT;AAEO,MAAM,oBAAuB,GAAA,OAClC,QACA,EAAA,aAAA,EACA,KACqB,KAAA;AAErB,EAAI,IAAA,QAAA,CAAS,WAAW,CAAG,EAAA;AACzB,IAAA,OAAO,EAAC;AAAA;AAGV,EAAA,MAAM,WAAc,GAAA,QAAA,CAAS,GAAI,CAAA,CAAA,OAAA,KAAW,QAAQ,UAAU,CAAA;AAC9D,EAAM,MAAA,UAAA,GAAa,cAChB,KAAM,CAAA,GAAG,EACT,GAAI,CAAA,CAAA,SAAA,KAAa,SAAU,CAAA,IAAA,EAAM,CAAA;AAEpC,EAAA,MAAM,MAAMD,uBAAgB,CAAA;AAAA,IAC1B,OAAS,EAAA,WAAA;AAAA,IACT,UAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,EAAE,QAAA,EAAa,GAAA,QAAA,CAAS,CAAC,CAAA;AAE/B,EAAI,IAAA;AACF,IAAM,MAAA,QAAA,GAAW,WAAY,CAAA,QAAA,EAAU,GAAG,CAAA;AAC1C,IAAA,MAAM,QAAW,GAAA,MAAM,OAAQ,CAAA,QAAA,EAAU,QAAU,EAAA;AAAA,MACjD,MAAQ,EAAA,KAAA;AAAA,MACR,OAAS,EAAA;AAAA,QACP,MAAQ,EAAA;AAAA;AACV,KACD,CAAE,CAAA,IAAA,CAAK,CAAQ,IAAA,KAAA,IAAA,CAAK,MAAM,CAAA;AAE3B,IAAA,IAAI,CAAC,QAAS,CAAA,MAAA,IAAU,QAAS,CAAA,MAAA,CAAO,WAAW,CAAG,EAAA;AACpD,MAAA,OAAO,EAAC;AAAA;AAGV,IAAoBC,uBAAA,CAAA,QAAA,EAAU,SAAS,MAAM,CAAA;AAC7C,IAAA,OAAO,QAAS,CAAA,MAAA;AAAA,WACT,KAAY,EAAA;AACnB,IAAA,IAAI,KAAM,CAAA,OAAA,CAAQ,QAAS,CAAA,wCAAwC,CAAG,EAAA;AACpE,MAAA,OAAO,EAAC;AAAA;AAEV,IAAM,MAAA,KAAA;AAAA;AAEV;AACsB,eAAA,gBAAA,CAAiB,KAAa,QAA0B,EAAA;AAC5E,EAAO,OAAA,OAAA,CAAQ,UAAU,GAAG,CAAA;AAC9B;AAUa,MAAA,aAAA,GAAgB,OAC3B,QAAA,EACA,QACmB,KAAA;AACnB,EAAA,MAAM,WAAW,MAAM,OAAA;AAAA,IACrB,QAAA;AAAA,IACA,CAAG,EAAAJ,aAAA,CAAU,QAAQ,CAAC,SAAS,QAAQ,CAAA,2BAAA,CAAA;AAAA,IACvC;AAAA,MACE,MAAQ,EAAA,KAAA;AAAA,MACR,OAAS,EAAA;AAAA,QACP,MAAQ,EAAA;AAAA;AACV;AACF,GACF;AACA,EAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,IAAM,MAAA,MAAMK,oBAAc,CAAA,YAAA,CAAa,QAAQ,CAAA;AAAA;AAGjD,EAAM,MAAA,KAAA,GAAS,MAAM,QAAA,CAAS,IAAK,EAAA;AACnC,EAAO,OAAA,KAAA;AACT;AASsB,eAAA,OAAA,CACpB,QACA,EAAA,GAAA,EACA,IACA,EAAA;AACA,EAAA,MAAM,WAAc,GAAA,IAAA,IAAQ,EAAE,MAAA,EAAQ,KAAM,EAAA;AAI5C,EAAA,WAAA,CAAY,OAAU,GAAA;AAAA,IACpB,GAAG,QAAS,CAAA,OAAA;AAAA,IACZ,eAAe,QAAS,CAAA,KAAA;AAAA,IACxB,GAAG,WAAY,CAAA;AAAA,GACjB;AACA,EAAO,OAAAC,sBAAA,CAAM,KAAK,WAAW,CAAA;AAC/B;;;;;;;;;;;;"}
1
+ {"version":3,"file":"api.cjs.js","sources":["../src/api.ts"],"sourcesContent":["import fetch, { RequestInit } from 'node-fetch';\nimport {\n Filter,\n Issue,\n Project,\n JiraQueryResults,\n} from '@axis-backstage/plugin-jira-dashboard-common';\n\nimport type { ConfigInstance } from './config';\nimport { jqlQueryBuilder } from './queries';\nimport type { JiraProject } from './lib';\nimport { getApiUrl, replaceProjectApiUrl, replaceIssuesApiUrl } from './lib';\nimport { ResponseError } from '@backstage/errors';\n\nexport const getProjectInfo = async (\n project: JiraProject,\n): Promise<Project> => {\n const { projectKey, instance } = project;\n const response = await callApi(\n instance,\n `${getApiUrl(instance)}project/${projectKey}`,\n {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n },\n );\n if (response.status !== 200) {\n throw Error(\n `Request failed with status code ${response.status}: ${response.statusText}`,\n );\n }\n\n const projectResponse = await response.json();\n replaceProjectApiUrl(project.instance, projectResponse);\n return projectResponse;\n};\n\nexport const getFilterById = async (\n id: string,\n instance: ConfigInstance,\n): Promise<Filter> => {\n const response = await callApi(\n instance,\n `${getApiUrl(instance)}filter/${id}`,\n {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n },\n );\n if (response.status !== 200) {\n throw Error(`${response.status}`);\n }\n const jsonResponse = await response.json();\n return { name: jsonResponse.name, query: jsonResponse.jql } as Filter;\n};\n\nexport const getQueryUrl = (instance: ConfigInstance, jql?: string): string => {\n const baseUrl = getApiUrl(instance);\n\n if (instance.useApiV3) {\n const baseUrlWithEndpoint = `${baseUrl}search/jql`;\n if (jql) {\n return `${baseUrlWithEndpoint}?jql=${jql}&fields=*all`;\n }\n return baseUrlWithEndpoint;\n }\n\n const baseUrlWithEndpoint = `${baseUrl}search`;\n if (jql) {\n return `${baseUrlWithEndpoint}?jql=${jql}`;\n }\n return baseUrlWithEndpoint;\n};\n\nexport const getIssuesByFilter = async (\n projects: JiraProject[],\n components: string[],\n query: string,\n): Promise<Issue[]> => {\n if (projects.length === 0) {\n return [];\n }\n\n // All projects are expected to share the same instance — callers (getJiraProjectsFromKeys)\n // stamp every project with the same ConfigInstance, so a single batched JQL query suffices.\n const { instance } = projects[0];\n const projectKeys = projects.map(p => p.projectKey);\n const jql = jqlQueryBuilder({ project: projectKeys, components, query });\n const queryUrl = getQueryUrl(instance, jql);\n\n const response = await callApi(instance, queryUrl, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n })\n .then(resp => resp.json())\n .catch(() => null);\n\n if (response?.errorMessages) {\n throw Error(\n `JQL returned Error: JQL - ${jql} with error: ${response?.errorMessages?.[0]}`,\n );\n }\n\n if (response?.issues) {\n replaceIssuesApiUrl(instance, response.issues);\n return response.issues;\n }\n\n return [];\n};\n\n/**\n * Options available for the Jira JQL query.\n *\n * @public\n */\nexport type SearchOptions = {\n expand?: string[];\n fields?: string[];\n fieldsByKey?: boolean;\n properties?: string[];\n startAt?: number;\n maxResults?: number;\n validateQuery?: string;\n};\n\n/**\n * Asynchronously searches for Jira issues using JQL.\n *\n * For more information about the available options, see the API documentation at:\n * https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issue-search/#api-rest-api-2-search-post\n *\n * @param config - A Backstage config\n * @param jqlQuery - A string containing the jql query.\n * @param options - Query options that will be passed on to the POST request.\n * @public\n */\nexport const searchJira = async (\n instance: ConfigInstance,\n jqlQuery: string,\n options: SearchOptions,\n): Promise<JiraQueryResults> => {\n const queryUrl = getQueryUrl(instance);\n const requestBody = { jql: jqlQuery, ...options };\n\n const response = await callApi(instance, queryUrl, {\n method: 'POST',\n body: JSON.stringify(requestBody),\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n });\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n const jsonResponse = (await response.json()) as JiraQueryResults;\n replaceIssuesApiUrl(instance, jsonResponse.issues);\n return jsonResponse;\n};\n\nexport const getIssuesByComponent = async (\n projects: JiraProject[],\n componentKeys: string,\n query?: string,\n): Promise<Issue[]> => {\n // Return an empty array if no projects are provided\n if (projects.length === 0) {\n return [];\n }\n\n const projectKeys = projects.map(project => project.projectKey);\n const components = componentKeys\n .split(',')\n .map(component => component.trim());\n\n const jql = jqlQueryBuilder({\n project: projectKeys,\n components,\n query,\n });\n\n const { instance } = projects[0];\n\n try {\n const queryUrl = getQueryUrl(instance, jql);\n const response = await callApi(instance, queryUrl, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n }).then(resp => resp.json());\n\n if (!response.issues || response.issues.length === 0) {\n return [];\n }\n\n replaceIssuesApiUrl(instance, response.issues);\n return response.issues;\n } catch (error: any) {\n if (error.message.includes(\"does not exist for the field 'project'\")) {\n return [];\n }\n throw error;\n }\n};\nexport async function getProjectAvatar(url: string, instance: ConfigInstance) {\n return callApi(instance, url);\n}\n\n/**\n * Get a single Jira issue by its key or ID.\n *\n * @param issueKey - The issue key (e.g., \"PROJ-123\") or ID\n * @param instance - The Jira instance configuration\n * @returns The Jira issue\n * @public\n */\nexport const getIssueByKey = async (\n issueKey: string,\n instance: ConfigInstance,\n): Promise<Issue> => {\n const response = await callApi(\n instance,\n `${getApiUrl(instance)}issue/${issueKey}?fields=summary,description`,\n {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n },\n );\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n const issue = (await response.json()) as Issue;\n return issue;\n};\n\n/**\n * Call the Jira API using fetch.\n *\n * This function injects the auth token and custom headers.\n *\n * @public\n */\nexport async function callApi(\n instance: ConfigInstance,\n url: string,\n init?: RequestInit,\n) {\n const requestInit = init ?? { method: 'GET' };\n\n // Inject custom headers from config, Authorization token and headers from the\n // request\n requestInit.headers = {\n ...instance.headers,\n Authorization: instance.token,\n ...requestInit.headers,\n };\n return fetch(url, requestInit);\n}\n"],"names":["getApiUrl","replaceProjectApiUrl","baseUrlWithEndpoint","jqlQueryBuilder","replaceIssuesApiUrl","ResponseError","fetch"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
2
  import { RootConfigService } from '@backstage/backend-plugin-api';
3
- import * as node_fetch from 'node-fetch';
4
- import { RequestInit } from 'node-fetch';
3
+ import fetch, { RequestInit } from 'node-fetch';
5
4
  import { Filter, JiraQueryResults } from '@axis-backstage/plugin-jira-dashboard-common';
6
5
 
7
6
  /**
@@ -102,7 +101,7 @@ declare const searchJira: (instance: ConfigInstance, jqlQuery: string, options:
102
101
  *
103
102
  * @public
104
103
  */
105
- declare function callApi(instance: ConfigInstance, url: string, init?: RequestInit): Promise<node_fetch.Response>;
104
+ declare function callApi(instance: ConfigInstance, url: string, init?: RequestInit): Promise<fetch.Response>;
106
105
 
107
106
  /**
108
107
  * Types for the arguments to the jqlQueryBuilder function.
@@ -36,7 +36,6 @@ const jiraDashboardPlugin = backendPluginApi.createBackendPlugin({
36
36
  await router.createRouter({
37
37
  auth,
38
38
  logger,
39
- rootConfig,
40
39
  config: config.JiraConfig.fromConfig(rootConfig),
41
40
  discovery,
42
41
  httpAuth,
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["import {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha';\nimport { createRouter } from './service/router';\nimport { JiraConfig } from './config';\nimport { createGetJiraTicketInfoAction } from './actions/createGetJiraTicketInfoAction';\n\n/**\n * The Jira Dashboard backend plugin.\n *\n * @public\n */\nexport const jiraDashboardPlugin = createBackendPlugin({\n pluginId: 'jira-dashboard',\n register(env) {\n env.registerInit({\n deps: {\n actionsRegistry: actionsRegistryServiceRef,\n auth: coreServices.auth,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n rootConfig: coreServices.rootConfig,\n discovery: coreServices.discovery,\n httpAuth: coreServices.httpAuth,\n userInfo: coreServices.userInfo,\n cache: coreServices.cache,\n },\n async init({\n actionsRegistry,\n auth,\n httpRouter,\n logger,\n rootConfig,\n discovery,\n httpAuth,\n userInfo,\n cache,\n }) {\n httpRouter.use(\n await createRouter({\n auth,\n logger,\n rootConfig,\n config: JiraConfig.fromConfig(rootConfig),\n discovery,\n httpAuth,\n userInfo,\n cache,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n createGetJiraTicketInfoAction({\n actionsRegistry,\n rootConfig,\n logger,\n });\n },\n });\n },\n});\n"],"names":["createBackendPlugin","actionsRegistryServiceRef","coreServices","createRouter","JiraConfig","createGetJiraTicketInfoAction"],"mappings":";;;;;;;;AAcO,MAAM,sBAAsBA,oCAAoB,CAAA;AAAA,EACrD,QAAU,EAAA,gBAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,eAAiB,EAAAC,+BAAA;AAAA,QACjB,MAAMC,6BAAa,CAAA,IAAA;AAAA,QACnB,YAAYA,6BAAa,CAAA,UAAA;AAAA,QACzB,QAAQA,6BAAa,CAAA,MAAA;AAAA,QACrB,YAAYA,6BAAa,CAAA,UAAA;AAAA,QACzB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,OAAOA,6BAAa,CAAA;AAAA,OACtB;AAAA,MACA,MAAM,IAAK,CAAA;AAAA,QACT,eAAA;AAAA,QACA,IAAA;AAAA,QACA,UAAA;AAAA,QACA,MAAA;AAAA,QACA,UAAA;AAAA,QACA,SAAA;AAAA,QACA,QAAA;AAAA,QACA,QAAA;AAAA,QACA;AAAA,OACC,EAAA;AACD,QAAW,UAAA,CAAA,GAAA;AAAA,UACT,MAAMC,mBAAa,CAAA;AAAA,YACjB,IAAA;AAAA,YACA,MAAA;AAAA,YACA,UAAA;AAAA,YACA,MAAA,EAAQC,iBAAW,CAAA,UAAA,CAAW,UAAU,CAAA;AAAA,YACxC,SAAA;AAAA,YACA,QAAA;AAAA,YACA,QAAA;AAAA,YACA;AAAA,WACD;AAAA,SACH;AACA,QAAA,UAAA,CAAW,aAAc,CAAA;AAAA,UACvB,IAAM,EAAA,SAAA;AAAA,UACN,KAAO,EAAA;AAAA,SACR,CAAA;AACD,QAA8BC,2DAAA,CAAA;AAAA,UAC5B,eAAA;AAAA,UACA,UAAA;AAAA,UACA;AAAA,SACD,CAAA;AAAA;AACH,KACD,CAAA;AAAA;AAEL,CAAC;;;;"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["import {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha';\nimport { createRouter } from './service/router';\nimport { JiraConfig } from './config';\nimport { createGetJiraTicketInfoAction } from './actions/createGetJiraTicketInfoAction';\n\n/**\n * The Jira Dashboard backend plugin.\n *\n * @public\n */\nexport const jiraDashboardPlugin = createBackendPlugin({\n pluginId: 'jira-dashboard',\n register(env) {\n env.registerInit({\n deps: {\n actionsRegistry: actionsRegistryServiceRef,\n auth: coreServices.auth,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n rootConfig: coreServices.rootConfig,\n discovery: coreServices.discovery,\n httpAuth: coreServices.httpAuth,\n userInfo: coreServices.userInfo,\n cache: coreServices.cache,\n },\n async init({\n actionsRegistry,\n auth,\n httpRouter,\n logger,\n rootConfig,\n discovery,\n httpAuth,\n userInfo,\n cache,\n }) {\n httpRouter.use(\n await createRouter({\n auth,\n logger,\n config: JiraConfig.fromConfig(rootConfig),\n discovery,\n httpAuth,\n userInfo,\n cache,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n createGetJiraTicketInfoAction({\n actionsRegistry,\n rootConfig,\n logger,\n });\n },\n });\n },\n});\n"],"names":["createBackendPlugin","actionsRegistryServiceRef","coreServices","createRouter","JiraConfig","createGetJiraTicketInfoAction"],"mappings":";;;;;;;;AAcO,MAAM,sBAAsBA,oCAAoB,CAAA;AAAA,EACrD,QAAU,EAAA,gBAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,eAAiB,EAAAC,+BAAA;AAAA,QACjB,MAAMC,6BAAa,CAAA,IAAA;AAAA,QACnB,YAAYA,6BAAa,CAAA,UAAA;AAAA,QACzB,QAAQA,6BAAa,CAAA,MAAA;AAAA,QACrB,YAAYA,6BAAa,CAAA,UAAA;AAAA,QACzB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,OAAOA,6BAAa,CAAA;AAAA,OACtB;AAAA,MACA,MAAM,IAAK,CAAA;AAAA,QACT,eAAA;AAAA,QACA,IAAA;AAAA,QACA,UAAA;AAAA,QACA,MAAA;AAAA,QACA,UAAA;AAAA,QACA,SAAA;AAAA,QACA,QAAA;AAAA,QACA,QAAA;AAAA,QACA;AAAA,OACC,EAAA;AACD,QAAW,UAAA,CAAA,GAAA;AAAA,UACT,MAAMC,mBAAa,CAAA;AAAA,YACjB,IAAA;AAAA,YACA,MAAA;AAAA,YACA,MAAA,EAAQC,iBAAW,CAAA,UAAA,CAAW,UAAU,CAAA;AAAA,YACxC,SAAA;AAAA,YACA,QAAA;AAAA,YACA,QAAA;AAAA,YACA;AAAA,WACD;AAAA,SACH;AACA,QAAA,UAAA,CAAW,aAAc,CAAA;AAAA,UACvB,IAAM,EAAA,SAAA;AAAA,UACN,KAAO,EAAA;AAAA,SACR,CAAA;AACD,QAA8BC,2DAAA,CAAA;AAAA,UAC5B,eAAA;AAAA,UACA,UAAA;AAAA,UACA;AAAA,SACD,CAAA;AAAA;AACH,KACD,CAAA;AAAA;AAEL,CAAC;;;;"}
@@ -3,7 +3,6 @@
3
3
  var express = require('express');
4
4
  var Router = require('express-promise-router');
5
5
  var stream = require('stream');
6
- var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
7
6
  var catalogModel = require('@backstage/catalog-model');
8
7
  var catalogClient = require('@backstage/catalog-client');
9
8
  var lib = require('../lib.cjs.js');
@@ -19,16 +18,7 @@ var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
19
18
  var stream__default = /*#__PURE__*/_interopDefaultCompat(stream);
20
19
 
21
20
  async function createRouter(options) {
22
- const {
23
- auth,
24
- logger,
25
- rootConfig,
26
- config,
27
- discovery,
28
- httpAuth,
29
- userInfo,
30
- cache
31
- } = options;
21
+ const { auth, logger, config, discovery, httpAuth, userInfo, cache } = options;
32
22
  const catalogClient$1 = new catalogClient.CatalogClient({ discoveryApi: discovery });
33
23
  logger.info("Initializing Jira Dashboard backend");
34
24
  const router = Router__default.default();
@@ -70,20 +60,21 @@ async function createRouter(options) {
70
60
  const projects = fullProjectKeys.map(
71
61
  (fullProjectKey) => lib.splitProjectKey(config, fullProjectKey)
72
62
  );
63
+ const projectResults = await Promise.allSettled(
64
+ projects.map((project) => service.getProjectResponse(project, cache))
65
+ );
73
66
  const projectResponses = [];
74
- for (const project of projects) {
75
- try {
76
- const projectData = await service.getProjectResponse(project, cache);
77
- projectResponses.push(projectData);
78
- } catch (err) {
67
+ for (const [i, result] of projectResults.entries()) {
68
+ if (result.status === "rejected") {
79
69
  logger.error(
80
- `Could not find Jira project ${project.fullProjectKey}: ${err.message}`
70
+ `Could not find Jira project ${projects[i].fullProjectKey}: ${result.reason?.message ?? result.reason}`
81
71
  );
82
72
  response.status(404).json({
83
- error: `Jira project not found with key ${project.fullProjectKey}`
73
+ error: `Jira project not found with key ${projects[i].fullProjectKey}`
84
74
  });
85
75
  return;
86
76
  }
77
+ projectResponses.push(result.value);
87
78
  }
88
79
  let userEntity;
89
80
  try {
@@ -253,8 +244,6 @@ async function createRouter(options) {
253
244
  ps.pipe(response);
254
245
  }
255
246
  );
256
- const middleware = rootHttpRouter.MiddlewareFactory.create({ logger, config: rootConfig });
257
- router.use(middleware.error());
258
247
  return router;
259
248
  }
260
249
 
@@ -1 +1 @@
1
- {"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["import express from 'express';\nimport Router from 'express-promise-router';\nimport stream from 'stream';\n\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport {\n AuthService,\n CacheService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n RootConfigService,\n UserInfoService,\n} from '@backstage/backend-plugin-api';\nimport { stringifyEntityRef, UserEntity } from '@backstage/catalog-model';\nimport { CatalogClient } from '@backstage/catalog-client';\n\nimport {\n type Filter,\n type JiraResponse,\n type Project,\n} from '@axis-backstage/plugin-jira-dashboard-common';\n\nimport { getAnnotations, splitProjectKey } from '../lib';\nimport {\n getFiltersFromAnnotations,\n getIssuesFromComponents,\n getIssuesFromFilters,\n getProjectResponse,\n getUserIssues,\n} from './service';\nimport { DEFAULT_MAX_RESULTS_USER_ISSUES } from './defaultValues';\nimport { getAssigneUser, getDefaultFiltersForUser } from '../filters';\nimport { getProjectAvatar } from '../api';\nimport type { ConfigInstance, JiraConfig } from '../config';\n\nexport interface RouterOptions {\n /**\n * Implementation of Authentication Service\n */\n auth: AuthService;\n /**\n * Implementation of Logger Service\n */\n logger: LoggerService;\n /**\n * Implementation of Config Service\n */\n rootConfig: RootConfigService;\n /**\n * Parsed Jira config\n */\n config: JiraConfig;\n /**\n * Implementation of Discovery Service\n */\n discovery: DiscoveryService;\n /**\n * Implementation of Http Authentication Service\n */\n httpAuth: HttpAuthService;\n /**\n * Implementation of User Info Service\n */\n userInfo: UserInfoService;\n /**\n * Implementation of Cache Service\n */\n cache: CacheService;\n}\n\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const {\n auth,\n logger,\n rootConfig,\n config,\n discovery,\n httpAuth,\n userInfo,\n cache,\n } = options;\n const catalogClient = new CatalogClient({ discoveryApi: discovery });\n\n logger.info('Initializing Jira Dashboard backend');\n\n const router = Router();\n router.use(express.json());\n\n router.get('/health', (_, response) => {\n logger.info('PONG!');\n response.json({ status: 'ok' });\n });\n\n router.get(\n '/dashboards/by-entity-ref/:kind/:namespace/:name',\n async (request, response) => {\n const { kind, namespace, name } = request.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const entity = await catalogClient.getEntityByRef(entityRef, { token });\n const {\n projectKeyAnnotation,\n jqlAnnotation,\n componentsAnnotation,\n filtersAnnotation,\n incomingIssuesAnnotation,\n componentRoadieAnnotation,\n } = getAnnotations(config);\n\n if (!entity) {\n logger.info(`No entity found for ${entityRef}`);\n response\n .status(500)\n .json({ error: `No entity found for ${entityRef}` });\n return;\n }\n\n const fullProjectKeys =\n entity.metadata.annotations?.[projectKeyAnnotation]?.split(',')!;\n\n if (!fullProjectKeys) {\n const error = `No jira.com/project-key annotation found for ${entityRef}`;\n logger.info(error);\n response.status(404).json(error);\n return;\n }\n\n const projects = fullProjectKeys.map(fullProjectKey =>\n splitProjectKey(config, fullProjectKey),\n );\n const projectResponses: Project[] = [];\n\n for (const project of projects) {\n try {\n const projectData = await getProjectResponse(project, cache);\n projectResponses.push(projectData);\n } catch (err: any) {\n logger.error(\n `Could not find Jira project ${project.fullProjectKey}: ${err.message}`,\n );\n response.status(404).json({\n error: `Jira project not found with key ${project.fullProjectKey}`,\n });\n return;\n }\n }\n\n let userEntity: UserEntity | undefined;\n\n try {\n const credentials = await httpAuth.credentials(request, {\n allow: ['user'],\n });\n const userIdentity = credentials.principal.userEntityRef;\n\n userEntity = (await catalogClient.getEntityByRef(userIdentity, {\n token,\n })) as UserEntity;\n } catch (err) {\n logger.warn('Could not find user identity');\n }\n\n let filters: Filter[] = [];\n\n const incomingStatus =\n entity.metadata.annotations?.[incomingIssuesAnnotation];\n\n filters = getDefaultFiltersForUser(\n projects[0].instance,\n userEntity,\n incomingStatus,\n );\n\n const customFilterAnnotations =\n entity.metadata.annotations?.[filtersAnnotation]?.split(',')!;\n\n if (customFilterAnnotations) {\n filters.push(\n ...(await getFiltersFromAnnotations(\n customFilterAnnotations,\n projects[0].instance,\n )),\n );\n }\n const instance = projects[0]?.instance;\n\n let components =\n entity.metadata.annotations?.[componentsAnnotation]?.split(',') ?? [];\n\n const jqlValue = entity.metadata.annotations?.[jqlAnnotation] ?? '';\n\n const projectKeys = projects.map(project => project.projectKey);\n let issues = await getIssuesFromFilters(\n projectKeys,\n components,\n filters,\n instance,\n cache,\n jqlValue,\n );\n\n /* Adding support for Roadie's component annotation */\n components = components.concat(\n entity.metadata.annotations?.[componentRoadieAnnotation]?.split(',') ??\n [],\n );\n\n if (components.length > 0) {\n const componentIssues = await getIssuesFromComponents(\n projectKeys,\n components,\n instance,\n cache,\n jqlValue,\n );\n issues = issues.concat(componentIssues);\n }\n\n const jiraResponse: JiraResponse = {\n project: projectResponses,\n data: issues,\n };\n\n response.json(jiraResponse);\n },\n );\n\n router.get('/dashboards/user-issues', async (request, response) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n\n const credentials = await httpAuth.credentials(request, {\n allow: ['user'],\n });\n\n // we ignore guest and service users, no issues in response\n if (!auth.isPrincipal(credentials, 'user')) {\n response.status(200).json([]);\n return;\n }\n\n const info = await userInfo.getUserInfo(credentials);\n\n const userEntity = (await catalogClient.getEntityByRef(info.userEntityRef, {\n token,\n })) as UserEntity;\n\n if (!userEntity) {\n const error = `User entity cannot be determined from ${info.userEntityRef}`;\n logger.info(error);\n response.status(400).json(error);\n return;\n }\n\n const getUserIssuesForInstance = async (instance: ConfigInstance) => {\n const username = getAssigneUser(instance, userEntity);\n\n const maxResults = Number(\n request.query.maxResults || DEFAULT_MAX_RESULTS_USER_ISSUES,\n );\n\n const filterName = (request.query?.filterName as string) || 'default';\n\n try {\n const issues = await getUserIssues(\n username,\n maxResults,\n instance,\n cache,\n filterName,\n );\n return { issues, error: undefined };\n } catch (error: any) {\n return { error };\n }\n };\n\n const issuesList = await Promise.all(\n config\n .getInstances()\n .map(instanceName =>\n getUserIssuesForInstance(config.getInstance(instanceName)),\n ),\n );\n\n const issues = issuesList.flatMap(list => list.issues ?? []);\n const errors = issuesList\n .flatMap(list => list.error)\n .filter((v): v is NonNullable<typeof v> => !!v);\n\n if (issues.length > 0 || errors.length === 0) {\n response.status(200).json(issues);\n } else {\n const messages =\n errors.length > 1\n ? `\\n ${errors.map(err => err.message).join('\\n ')}`\n : ` ${errors[0].message}`;\n\n logger.error(`Error during getting user issues:${messages}`);\n response.status(503).json({\n error: `Error during getting user issues:${messages}`,\n });\n }\n });\n\n router.get(\n '/avatar/by-entity-ref/:kind/:namespace/:name',\n async (request, response) => {\n const { kind, namespace, name } = request.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const entity = await catalogClient.getEntityByRef(entityRef, { token });\n const { projectKeyAnnotation } = getAnnotations(config);\n\n if (!entity) {\n logger.info(`No entity found for ${entityRef}`);\n response\n .status(500)\n .json({ error: `No entity found for ${entityRef}` });\n return;\n }\n\n const fullProjectKeys =\n entity.metadata.annotations?.[projectKeyAnnotation]?.split(',')!;\n\n if (!fullProjectKeys) {\n const error = `No jira.com/project-key annotation found for ${entityRef}`;\n logger.info(error);\n response.status(404).json(error);\n return;\n }\n\n const projects = fullProjectKeys.map(fullProjectKey =>\n splitProjectKey(config, fullProjectKey),\n );\n\n const projectResponse = await getProjectResponse(projects[0], cache);\n\n if (!projectResponse) {\n logger.error('Could not find project in Jira');\n response.status(400).json({\n error: `No Jira project found for project key ${projects[0].projectKey}`,\n });\n return;\n }\n\n const url = projectResponse.avatarUrls['48x48'];\n\n const avatar = await getProjectAvatar(url, projects[0].instance);\n\n const ps = new stream.PassThrough();\n const val = avatar.headers.get('content-type');\n\n response.setHeader('content-type', val ?? '');\n stream.pipeline(avatar.body, ps, err => {\n if (err) {\n logger.error(`${err}`);\n response.sendStatus(400);\n }\n return;\n });\n ps.pipe(response);\n },\n );\n\n const middleware = MiddlewareFactory.create({ logger, config: rootConfig });\n\n router.use(middleware.error());\n return router;\n}\n"],"names":["catalogClient","CatalogClient","Router","express","stringifyEntityRef","getAnnotations","splitProjectKey","getProjectResponse","filters","getDefaultFiltersForUser","getFiltersFromAnnotations","getIssuesFromFilters","getIssuesFromComponents","getAssigneUser","DEFAULT_MAX_RESULTS_USER_ISSUES","issues","getUserIssues","getProjectAvatar","stream","MiddlewareFactory"],"mappings":";;;;;;;;;;;;;;;;;;;;AAuEA,eAAsB,aACpB,OACyB,EAAA;AACzB,EAAM,MAAA;AAAA,IACJ,IAAA;AAAA,IACA,MAAA;AAAA,IACA,UAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACE,GAAA,OAAA;AACJ,EAAA,MAAMA,kBAAgB,IAAIC,2BAAA,CAAc,EAAE,YAAA,EAAc,WAAW,CAAA;AAEnE,EAAA,MAAA,CAAO,KAAK,qCAAqC,CAAA;AAEjD,EAAA,MAAM,SAASC,uBAAO,EAAA;AACtB,EAAO,MAAA,CAAA,GAAA,CAAIC,wBAAQ,CAAA,IAAA,EAAM,CAAA;AAEzB,EAAA,MAAA,CAAO,GAAI,CAAA,SAAA,EAAW,CAAC,CAAA,EAAG,QAAa,KAAA;AACrC,IAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,IAAA,QAAA,CAAS,IAAK,CAAA,EAAE,MAAQ,EAAA,IAAA,EAAM,CAAA;AAAA,GAC/B,CAAA;AAED,EAAO,MAAA,CAAA,GAAA;AAAA,IACL,kDAAA;AAAA,IACA,OAAO,SAAS,QAAa,KAAA;AAC3B,MAAA,MAAM,EAAE,IAAA,EAAM,SAAW,EAAA,IAAA,KAAS,OAAQ,CAAA,MAAA;AAC1C,MAAA,MAAM,YAAYC,+BAAmB,CAAA,EAAE,IAAM,EAAA,SAAA,EAAW,MAAM,CAAA;AAC9D,MAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,KAAK,qBAAsB,CAAA;AAAA,QACjD,UAAA,EAAY,MAAM,IAAA,CAAK,wBAAyB,EAAA;AAAA,QAChD,cAAgB,EAAA;AAAA,OACjB,CAAA;AACD,MAAA,MAAM,SAAS,MAAMJ,eAAA,CAAc,eAAe,SAAW,EAAA,EAAE,OAAO,CAAA;AACtE,MAAM,MAAA;AAAA,QACJ,oBAAA;AAAA,QACA,aAAA;AAAA,QACA,oBAAA;AAAA,QACA,iBAAA;AAAA,QACA,wBAAA;AAAA,QACA;AAAA,OACF,GAAIK,mBAAe,MAAM,CAAA;AAEzB,MAAA,IAAI,CAAC,MAAQ,EAAA;AACX,QAAO,MAAA,CAAA,IAAA,CAAK,CAAuB,oBAAA,EAAA,SAAS,CAAE,CAAA,CAAA;AAC9C,QACG,QAAA,CAAA,MAAA,CAAO,GAAG,CACV,CAAA,IAAA,CAAK,EAAE,KAAO,EAAA,CAAA,oBAAA,EAAuB,SAAS,CAAA,CAAA,EAAI,CAAA;AACrD,QAAA;AAAA;AAGF,MAAA,MAAM,kBACJ,MAAO,CAAA,QAAA,CAAS,cAAc,oBAAoB,CAAA,EAAG,MAAM,GAAG,CAAA;AAEhE,MAAA,IAAI,CAAC,eAAiB,EAAA;AACpB,QAAM,MAAA,KAAA,GAAQ,gDAAgD,SAAS,CAAA,CAAA;AACvE,QAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AACjB,QAAA,QAAA,CAAS,MAAO,CAAA,GAAG,CAAE,CAAA,IAAA,CAAK,KAAK,CAAA;AAC/B,QAAA;AAAA;AAGF,MAAA,MAAM,WAAW,eAAgB,CAAA,GAAA;AAAA,QAAI,CAAA,cAAA,KACnCC,mBAAgB,CAAA,MAAA,EAAQ,cAAc;AAAA,OACxC;AACA,MAAA,MAAM,mBAA8B,EAAC;AAErC,MAAA,KAAA,MAAW,WAAW,QAAU,EAAA;AAC9B,QAAI,IAAA;AACF,UAAA,MAAM,WAAc,GAAA,MAAMC,0BAAmB,CAAA,OAAA,EAAS,KAAK,CAAA;AAC3D,UAAA,gBAAA,CAAiB,KAAK,WAAW,CAAA;AAAA,iBAC1B,GAAU,EAAA;AACjB,UAAO,MAAA,CAAA,KAAA;AAAA,YACL,CAA+B,4BAAA,EAAA,OAAA,CAAQ,cAAc,CAAA,EAAA,EAAK,IAAI,OAAO,CAAA;AAAA,WACvE;AACA,UAAS,QAAA,CAAA,MAAA,CAAO,GAAG,CAAA,CAAE,IAAK,CAAA;AAAA,YACxB,KAAA,EAAO,CAAmC,gCAAA,EAAA,OAAA,CAAQ,cAAc,CAAA;AAAA,WACjE,CAAA;AACD,UAAA;AAAA;AACF;AAGF,MAAI,IAAA,UAAA;AAEJ,MAAI,IAAA;AACF,QAAA,MAAM,WAAc,GAAA,MAAM,QAAS,CAAA,WAAA,CAAY,OAAS,EAAA;AAAA,UACtD,KAAA,EAAO,CAAC,MAAM;AAAA,SACf,CAAA;AACD,QAAM,MAAA,YAAA,GAAe,YAAY,SAAU,CAAA,aAAA;AAE3C,QAAc,UAAA,GAAA,MAAMP,eAAc,CAAA,cAAA,CAAe,YAAc,EAAA;AAAA,UAC7D;AAAA,SACD,CAAA;AAAA,eACM,GAAK,EAAA;AACZ,QAAA,MAAA,CAAO,KAAK,8BAA8B,CAAA;AAAA;AAG5C,MAAA,IAAIQ,YAAoB,EAAC;AAEzB,MAAA,MAAM,cACJ,GAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAc,wBAAwB,CAAA;AAExD,MAAUA,SAAA,GAAAC,gCAAA;AAAA,QACR,QAAA,CAAS,CAAC,CAAE,CAAA,QAAA;AAAA,QACZ,UAAA;AAAA,QACA;AAAA,OACF;AAEA,MAAA,MAAM,0BACJ,MAAO,CAAA,QAAA,CAAS,cAAc,iBAAiB,CAAA,EAAG,MAAM,GAAG,CAAA;AAE7D,MAAA,IAAI,uBAAyB,EAAA;AAC3B,QAAQD,SAAA,CAAA,IAAA;AAAA,UACN,GAAI,MAAME,iCAAA;AAAA,YACR,uBAAA;AAAA,YACA,QAAA,CAAS,CAAC,CAAE,CAAA;AAAA;AACd,SACF;AAAA;AAEF,MAAM,MAAA,QAAA,GAAW,QAAS,CAAA,CAAC,CAAG,EAAA,QAAA;AAE9B,MAAI,IAAA,UAAA,GACF,OAAO,QAAS,CAAA,WAAA,GAAc,oBAAoB,CAAG,EAAA,KAAA,CAAM,GAAG,CAAA,IAAK,EAAC;AAEtE,MAAA,MAAM,QAAW,GAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAc,aAAa,CAAK,IAAA,EAAA;AAEjE,MAAA,MAAM,WAAc,GAAA,QAAA,CAAS,GAAI,CAAA,CAAA,OAAA,KAAW,QAAQ,UAAU,CAAA;AAC9D,MAAA,IAAI,SAAS,MAAMC,4BAAA;AAAA,QACjB,WAAA;AAAA,QACA,UAAA;AAAA,QACAH,SAAA;AAAA,QACA,QAAA;AAAA,QACA,KAAA;AAAA,QACA;AAAA,OACF;AAGA,MAAA,UAAA,GAAa,UAAW,CAAA,MAAA;AAAA,QACtB,MAAA,CAAO,SAAS,WAAc,GAAA,yBAAyB,GAAG,KAAM,CAAA,GAAG,KACjE;AAAC,OACL;AAEA,MAAI,IAAA,UAAA,CAAW,SAAS,CAAG,EAAA;AACzB,QAAA,MAAM,kBAAkB,MAAMI,+BAAA;AAAA,UAC5B,WAAA;AAAA,UACA,UAAA;AAAA,UACA,QAAA;AAAA,UACA,KAAA;AAAA,UACA;AAAA,SACF;AACA,QAAS,MAAA,GAAA,MAAA,CAAO,OAAO,eAAe,CAAA;AAAA;AAGxC,MAAA,MAAM,YAA6B,GAAA;AAAA,QACjC,OAAS,EAAA,gBAAA;AAAA,QACT,IAAM,EAAA;AAAA,OACR;AAEA,MAAA,QAAA,CAAS,KAAK,YAAY,CAAA;AAAA;AAC5B,GACF;AAEA,EAAA,MAAA,CAAO,GAAI,CAAA,yBAAA,EAA2B,OAAO,OAAA,EAAS,QAAa,KAAA;AACjE,IAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,KAAK,qBAAsB,CAAA;AAAA,MACjD,UAAA,EAAY,MAAM,IAAA,CAAK,wBAAyB,EAAA;AAAA,MAChD,cAAgB,EAAA;AAAA,KACjB,CAAA;AAED,IAAA,MAAM,WAAc,GAAA,MAAM,QAAS,CAAA,WAAA,CAAY,OAAS,EAAA;AAAA,MACtD,KAAA,EAAO,CAAC,MAAM;AAAA,KACf,CAAA;AAGD,IAAA,IAAI,CAAC,IAAA,CAAK,WAAY,CAAA,WAAA,EAAa,MAAM,CAAG,EAAA;AAC1C,MAAA,QAAA,CAAS,MAAO,CAAA,GAAG,CAAE,CAAA,IAAA,CAAK,EAAE,CAAA;AAC5B,MAAA;AAAA;AAGF,IAAA,MAAM,IAAO,GAAA,MAAM,QAAS,CAAA,WAAA,CAAY,WAAW,CAAA;AAEnD,IAAA,MAAM,UAAc,GAAA,MAAMZ,eAAc,CAAA,cAAA,CAAe,KAAK,aAAe,EAAA;AAAA,MACzE;AAAA,KACD,CAAA;AAED,IAAA,IAAI,CAAC,UAAY,EAAA;AACf,MAAM,MAAA,KAAA,GAAQ,CAAyC,sCAAA,EAAA,IAAA,CAAK,aAAa,CAAA,CAAA;AACzE,MAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AACjB,MAAA,QAAA,CAAS,MAAO,CAAA,GAAG,CAAE,CAAA,IAAA,CAAK,KAAK,CAAA;AAC/B,MAAA;AAAA;AAGF,IAAM,MAAA,wBAAA,GAA2B,OAAO,QAA6B,KAAA;AACnE,MAAM,MAAA,QAAA,GAAWa,sBAAe,CAAA,QAAA,EAAU,UAAU,CAAA;AAEpD,MAAA,MAAM,UAAa,GAAA,MAAA;AAAA,QACjB,OAAA,CAAQ,MAAM,UAAc,IAAAC;AAAA,OAC9B;AAEA,MAAM,MAAA,UAAA,GAAc,OAAQ,CAAA,KAAA,EAAO,UAAyB,IAAA,SAAA;AAE5D,MAAI,IAAA;AACF,QAAA,MAAMC,UAAS,MAAMC,qBAAA;AAAA,UACnB,QAAA;AAAA,UACA,UAAA;AAAA,UACA,QAAA;AAAA,UACA,KAAA;AAAA,UACA;AAAA,SACF;AACA,QAAA,OAAO,EAAE,MAAA,EAAAD,OAAQ,EAAA,KAAA,EAAO,KAAU,CAAA,EAAA;AAAA,eAC3B,KAAY,EAAA;AACnB,QAAA,OAAO,EAAE,KAAM,EAAA;AAAA;AACjB,KACF;AAEA,IAAM,MAAA,UAAA,GAAa,MAAM,OAAQ,CAAA,GAAA;AAAA,MAC/B,MAAA,CACG,cACA,CAAA,GAAA;AAAA,QAAI,CACH,YAAA,KAAA,wBAAA,CAAyB,MAAO,CAAA,WAAA,CAAY,YAAY,CAAC;AAAA;AAC3D,KACJ;AAEA,IAAA,MAAM,SAAS,UAAW,CAAA,OAAA,CAAQ,UAAQ,IAAK,CAAA,MAAA,IAAU,EAAE,CAAA;AAC3D,IAAA,MAAM,MAAS,GAAA,UAAA,CACZ,OAAQ,CAAA,CAAA,IAAA,KAAQ,IAAK,CAAA,KAAK,CAC1B,CAAA,MAAA,CAAO,CAAC,CAAA,KAAkC,CAAC,CAAC,CAAC,CAAA;AAEhD,IAAA,IAAI,MAAO,CAAA,MAAA,GAAS,CAAK,IAAA,MAAA,CAAO,WAAW,CAAG,EAAA;AAC5C,MAAA,QAAA,CAAS,MAAO,CAAA,GAAG,CAAE,CAAA,IAAA,CAAK,MAAM,CAAA;AAAA,KAC3B,MAAA;AACL,MAAM,MAAA,QAAA,GACJ,MAAO,CAAA,MAAA,GAAS,CACZ,GAAA;AAAA,EAAA,EAAO,MAAO,CAAA,GAAA,CAAI,CAAO,GAAA,KAAA,GAAA,CAAI,OAAO,CAAE,CAAA,IAAA,CAAK,MAAM,CAAC,CAClD,CAAA,GAAA,CAAA,CAAA,EAAI,MAAO,CAAA,CAAC,EAAE,OAAO,CAAA,CAAA;AAE3B,MAAO,MAAA,CAAA,KAAA,CAAM,CAAoC,iCAAA,EAAA,QAAQ,CAAE,CAAA,CAAA;AAC3D,MAAS,QAAA,CAAA,MAAA,CAAO,GAAG,CAAA,CAAE,IAAK,CAAA;AAAA,QACxB,KAAA,EAAO,oCAAoC,QAAQ,CAAA;AAAA,OACpD,CAAA;AAAA;AACH,GACD,CAAA;AAED,EAAO,MAAA,CAAA,GAAA;AAAA,IACL,8CAAA;AAAA,IACA,OAAO,SAAS,QAAa,KAAA;AAC3B,MAAA,MAAM,EAAE,IAAA,EAAM,SAAW,EAAA,IAAA,KAAS,OAAQ,CAAA,MAAA;AAC1C,MAAA,MAAM,YAAYX,+BAAmB,CAAA,EAAE,IAAM,EAAA,SAAA,EAAW,MAAM,CAAA;AAC9D,MAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,KAAK,qBAAsB,CAAA;AAAA,QACjD,UAAA,EAAY,MAAM,IAAA,CAAK,wBAAyB,EAAA;AAAA,QAChD,cAAgB,EAAA;AAAA,OACjB,CAAA;AACD,MAAA,MAAM,SAAS,MAAMJ,eAAA,CAAc,eAAe,SAAW,EAAA,EAAE,OAAO,CAAA;AACtE,MAAA,MAAM,EAAE,oBAAA,EAAyB,GAAAK,kBAAA,CAAe,MAAM,CAAA;AAEtD,MAAA,IAAI,CAAC,MAAQ,EAAA;AACX,QAAO,MAAA,CAAA,IAAA,CAAK,CAAuB,oBAAA,EAAA,SAAS,CAAE,CAAA,CAAA;AAC9C,QACG,QAAA,CAAA,MAAA,CAAO,GAAG,CACV,CAAA,IAAA,CAAK,EAAE,KAAO,EAAA,CAAA,oBAAA,EAAuB,SAAS,CAAA,CAAA,EAAI,CAAA;AACrD,QAAA;AAAA;AAGF,MAAA,MAAM,kBACJ,MAAO,CAAA,QAAA,CAAS,cAAc,oBAAoB,CAAA,EAAG,MAAM,GAAG,CAAA;AAEhE,MAAA,IAAI,CAAC,eAAiB,EAAA;AACpB,QAAM,MAAA,KAAA,GAAQ,gDAAgD,SAAS,CAAA,CAAA;AACvE,QAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AACjB,QAAA,QAAA,CAAS,MAAO,CAAA,GAAG,CAAE,CAAA,IAAA,CAAK,KAAK,CAAA;AAC/B,QAAA;AAAA;AAGF,MAAA,MAAM,WAAW,eAAgB,CAAA,GAAA;AAAA,QAAI,CAAA,cAAA,KACnCC,mBAAgB,CAAA,MAAA,EAAQ,cAAc;AAAA,OACxC;AAEA,MAAA,MAAM,kBAAkB,MAAMC,0BAAA,CAAmB,QAAS,CAAA,CAAC,GAAG,KAAK,CAAA;AAEnE,MAAA,IAAI,CAAC,eAAiB,EAAA;AACpB,QAAA,MAAA,CAAO,MAAM,gCAAgC,CAAA;AAC7C,QAAS,QAAA,CAAA,MAAA,CAAO,GAAG,CAAA,CAAE,IAAK,CAAA;AAAA,UACxB,KAAO,EAAA,CAAA,sCAAA,EAAyC,QAAS,CAAA,CAAC,EAAE,UAAU,CAAA;AAAA,SACvE,CAAA;AACD,QAAA;AAAA;AAGF,MAAM,MAAA,GAAA,GAAM,eAAgB,CAAA,UAAA,CAAW,OAAO,CAAA;AAE9C,MAAA,MAAM,SAAS,MAAMU,oBAAA,CAAiB,KAAK,QAAS,CAAA,CAAC,EAAE,QAAQ,CAAA;AAE/D,MAAM,MAAA,EAAA,GAAK,IAAIC,uBAAA,CAAO,WAAY,EAAA;AAClC,MAAA,MAAM,GAAM,GAAA,MAAA,CAAO,OAAQ,CAAA,GAAA,CAAI,cAAc,CAAA;AAE7C,MAAS,QAAA,CAAA,SAAA,CAAU,cAAgB,EAAA,GAAA,IAAO,EAAE,CAAA;AAC5C,MAAAA,uBAAA,CAAO,QAAS,CAAA,MAAA,CAAO,IAAM,EAAA,EAAA,EAAI,CAAO,GAAA,KAAA;AACtC,QAAA,IAAI,GAAK,EAAA;AACP,UAAO,MAAA,CAAA,KAAA,CAAM,CAAG,EAAA,GAAG,CAAE,CAAA,CAAA;AACrB,UAAA,QAAA,CAAS,WAAW,GAAG,CAAA;AAAA;AAEzB,QAAA;AAAA,OACD,CAAA;AACD,MAAA,EAAA,CAAG,KAAK,QAAQ,CAAA;AAAA;AAClB,GACF;AAEA,EAAA,MAAM,aAAaC,gCAAkB,CAAA,MAAA,CAAO,EAAE,MAAQ,EAAA,MAAA,EAAQ,YAAY,CAAA;AAE1E,EAAO,MAAA,CAAA,GAAA,CAAI,UAAW,CAAA,KAAA,EAAO,CAAA;AAC7B,EAAO,OAAA,MAAA;AACT;;;;"}
1
+ {"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["import express from 'express';\nimport Router from 'express-promise-router';\nimport stream from 'stream';\n\nimport {\n AuthService,\n CacheService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n UserInfoService,\n} from '@backstage/backend-plugin-api';\nimport { stringifyEntityRef, UserEntity } from '@backstage/catalog-model';\nimport { CatalogClient } from '@backstage/catalog-client';\n\nimport {\n type Filter,\n type JiraResponse,\n type Project,\n} from '@axis-backstage/plugin-jira-dashboard-common';\n\nimport { getAnnotations, splitProjectKey } from '../lib';\nimport {\n getFiltersFromAnnotations,\n getIssuesFromComponents,\n getIssuesFromFilters,\n getProjectResponse,\n getUserIssues,\n} from './service';\nimport { DEFAULT_MAX_RESULTS_USER_ISSUES } from './defaultValues';\nimport { getAssigneUser, getDefaultFiltersForUser } from '../filters';\nimport { getProjectAvatar } from '../api';\nimport type { ConfigInstance, JiraConfig } from '../config';\n\nexport interface RouterOptions {\n /**\n * Implementation of Authentication Service\n */\n auth: AuthService;\n /**\n * Implementation of Logger Service\n */\n logger: LoggerService;\n /**\n * Parsed Jira config\n */\n config: JiraConfig;\n /**\n * Implementation of Discovery Service\n */\n discovery: DiscoveryService;\n /**\n * Implementation of Http Authentication Service\n */\n httpAuth: HttpAuthService;\n /**\n * Implementation of User Info Service\n */\n userInfo: UserInfoService;\n /**\n * Implementation of Cache Service\n */\n cache: CacheService;\n}\n\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { auth, logger, config, discovery, httpAuth, userInfo, cache } =\n options;\n const catalogClient = new CatalogClient({ discoveryApi: discovery });\n\n logger.info('Initializing Jira Dashboard backend');\n\n const router = Router();\n router.use(express.json());\n\n router.get('/health', (_, response) => {\n logger.info('PONG!');\n response.json({ status: 'ok' });\n });\n\n router.get(\n '/dashboards/by-entity-ref/:kind/:namespace/:name',\n async (request, response) => {\n const { kind, namespace, name } = request.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const entity = await catalogClient.getEntityByRef(entityRef, { token });\n const {\n projectKeyAnnotation,\n jqlAnnotation,\n componentsAnnotation,\n filtersAnnotation,\n incomingIssuesAnnotation,\n componentRoadieAnnotation,\n } = getAnnotations(config);\n\n if (!entity) {\n logger.info(`No entity found for ${entityRef}`);\n response\n .status(500)\n .json({ error: `No entity found for ${entityRef}` });\n return;\n }\n\n const fullProjectKeys =\n entity.metadata.annotations?.[projectKeyAnnotation]?.split(',')!;\n\n if (!fullProjectKeys) {\n const error = `No jira.com/project-key annotation found for ${entityRef}`;\n logger.info(error);\n response.status(404).json(error);\n return;\n }\n\n const projects = fullProjectKeys.map(fullProjectKey =>\n splitProjectKey(config, fullProjectKey),\n );\n const projectResults = await Promise.allSettled(\n projects.map(project => getProjectResponse(project, cache)),\n );\n\n const projectResponses: Project[] = [];\n for (const [i, result] of projectResults.entries()) {\n if (result.status === 'rejected') {\n logger.error(\n `Could not find Jira project ${projects[i].fullProjectKey}: ${\n result.reason?.message ?? result.reason\n }`,\n );\n response.status(404).json({\n error: `Jira project not found with key ${projects[i].fullProjectKey}`,\n });\n return;\n }\n projectResponses.push(result.value);\n }\n\n let userEntity: UserEntity | undefined;\n\n try {\n const credentials = await httpAuth.credentials(request, {\n allow: ['user'],\n });\n const userIdentity = credentials.principal.userEntityRef;\n\n userEntity = (await catalogClient.getEntityByRef(userIdentity, {\n token,\n })) as UserEntity;\n } catch (err) {\n logger.warn('Could not find user identity');\n }\n\n let filters: Filter[] = [];\n\n const incomingStatus =\n entity.metadata.annotations?.[incomingIssuesAnnotation];\n\n filters = getDefaultFiltersForUser(\n projects[0].instance,\n userEntity,\n incomingStatus,\n );\n\n const customFilterAnnotations =\n entity.metadata.annotations?.[filtersAnnotation]?.split(',')!;\n\n if (customFilterAnnotations) {\n filters.push(\n ...(await getFiltersFromAnnotations(\n customFilterAnnotations,\n projects[0].instance,\n )),\n );\n }\n const instance = projects[0]?.instance;\n\n let components =\n entity.metadata.annotations?.[componentsAnnotation]?.split(',') ?? [];\n\n const jqlValue = entity.metadata.annotations?.[jqlAnnotation] ?? '';\n\n const projectKeys = projects.map(project => project.projectKey);\n let issues = await getIssuesFromFilters(\n projectKeys,\n components,\n filters,\n instance,\n cache,\n jqlValue,\n );\n\n /* Adding support for Roadie's component annotation */\n components = components.concat(\n entity.metadata.annotations?.[componentRoadieAnnotation]?.split(',') ??\n [],\n );\n\n if (components.length > 0) {\n const componentIssues = await getIssuesFromComponents(\n projectKeys,\n components,\n instance,\n cache,\n jqlValue,\n );\n issues = issues.concat(componentIssues);\n }\n\n const jiraResponse: JiraResponse = {\n project: projectResponses,\n data: issues,\n };\n\n response.json(jiraResponse);\n },\n );\n\n router.get('/dashboards/user-issues', async (request, response) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n\n const credentials = await httpAuth.credentials(request, {\n allow: ['user'],\n });\n\n // we ignore guest and service users, no issues in response\n if (!auth.isPrincipal(credentials, 'user')) {\n response.status(200).json([]);\n return;\n }\n\n const info = await userInfo.getUserInfo(credentials);\n\n const userEntity = (await catalogClient.getEntityByRef(info.userEntityRef, {\n token,\n })) as UserEntity;\n\n if (!userEntity) {\n const error = `User entity cannot be determined from ${info.userEntityRef}`;\n logger.info(error);\n response.status(400).json(error);\n return;\n }\n\n const getUserIssuesForInstance = async (instance: ConfigInstance) => {\n const username = getAssigneUser(instance, userEntity);\n\n const maxResults = Number(\n request.query.maxResults || DEFAULT_MAX_RESULTS_USER_ISSUES,\n );\n\n const filterName = (request.query?.filterName as string) || 'default';\n\n try {\n const issues = await getUserIssues(\n username,\n maxResults,\n instance,\n cache,\n filterName,\n );\n return { issues, error: undefined };\n } catch (error: any) {\n return { error };\n }\n };\n\n const issuesList = await Promise.all(\n config\n .getInstances()\n .map(instanceName =>\n getUserIssuesForInstance(config.getInstance(instanceName)),\n ),\n );\n\n const issues = issuesList.flatMap(list => list.issues ?? []);\n const errors = issuesList\n .flatMap(list => list.error)\n .filter((v): v is NonNullable<typeof v> => !!v);\n\n if (issues.length > 0 || errors.length === 0) {\n response.status(200).json(issues);\n } else {\n const messages =\n errors.length > 1\n ? `\\n ${errors.map(err => err.message).join('\\n ')}`\n : ` ${errors[0].message}`;\n\n logger.error(`Error during getting user issues:${messages}`);\n response.status(503).json({\n error: `Error during getting user issues:${messages}`,\n });\n }\n });\n\n router.get(\n '/avatar/by-entity-ref/:kind/:namespace/:name',\n async (request, response) => {\n const { kind, namespace, name } = request.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const entity = await catalogClient.getEntityByRef(entityRef, { token });\n const { projectKeyAnnotation } = getAnnotations(config);\n\n if (!entity) {\n logger.info(`No entity found for ${entityRef}`);\n response\n .status(500)\n .json({ error: `No entity found for ${entityRef}` });\n return;\n }\n\n const fullProjectKeys =\n entity.metadata.annotations?.[projectKeyAnnotation]?.split(',')!;\n\n if (!fullProjectKeys) {\n const error = `No jira.com/project-key annotation found for ${entityRef}`;\n logger.info(error);\n response.status(404).json(error);\n return;\n }\n\n const projects = fullProjectKeys.map(fullProjectKey =>\n splitProjectKey(config, fullProjectKey),\n );\n\n const projectResponse = await getProjectResponse(projects[0], cache);\n\n if (!projectResponse) {\n logger.error('Could not find project in Jira');\n response.status(400).json({\n error: `No Jira project found for project key ${projects[0].projectKey}`,\n });\n return;\n }\n\n const url = projectResponse.avatarUrls['48x48'];\n\n const avatar = await getProjectAvatar(url, projects[0].instance);\n\n const ps = new stream.PassThrough();\n const val = avatar.headers.get('content-type');\n\n response.setHeader('content-type', val ?? '');\n stream.pipeline(avatar.body, ps, err => {\n if (err) {\n logger.error(`${err}`);\n response.sendStatus(400);\n }\n return;\n });\n ps.pipe(response);\n },\n );\n\n return router;\n}\n"],"names":["catalogClient","CatalogClient","Router","express","stringifyEntityRef","getAnnotations","splitProjectKey","getProjectResponse","filters","getDefaultFiltersForUser","getFiltersFromAnnotations","getIssuesFromFilters","getIssuesFromComponents","getAssigneUser","DEFAULT_MAX_RESULTS_USER_ISSUES","issues","getUserIssues","getProjectAvatar","stream"],"mappings":"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"}
@@ -65,39 +65,36 @@ const getUserIssues = async (username, maxResults, config, cache, filterName) =>
65
65
  });
66
66
  };
67
67
  const getFiltersFromAnnotations = async (annotations, config) => {
68
- const filters = [];
69
- for (const filter of annotations) {
70
- try {
71
- const response = await api.getFilterById(filter, config);
72
- filters.push(response);
73
- } catch (err) {
68
+ const results = await Promise.allSettled(
69
+ annotations.map((filter) => api.getFilterById(filter, config))
70
+ );
71
+ return results.map((result, i) => {
72
+ if (result.status === "rejected") {
74
73
  console.warn(
75
- `${err.message} : Could not find filter with filter id ${filter}`
74
+ `${result.reason.message} : Could not find filter with filter id ${annotations[i]}`
76
75
  );
76
+ return null;
77
77
  }
78
- }
79
- return filters;
78
+ return result.value;
79
+ }).filter((filter) => filter !== null);
80
80
  };
81
81
  async function getJiraProjectsFromKeys(projectKeys, instance, cache) {
82
- const jiraProjects = [];
83
- for (const key of projectKeys) {
84
- const cachedProject = await cache.get(key);
85
- let projectInfo;
86
- if (cachedProject) {
87
- projectInfo = cachedProject;
88
- } else {
89
- projectInfo = await api.getProjectInfo({
82
+ return Promise.all(
83
+ projectKeys.map(async (key) => {
84
+ const cachedProject = await cache.get(key);
85
+ const projectInfo = cachedProject ?? await api.getProjectInfo({
90
86
  projectKey: key,
91
87
  instance});
92
- cache.set(key, projectInfo, { ttl: instance.cacheTtl });
93
- }
94
- jiraProjects.push({
95
- instance,
96
- fullProjectKey: projectInfo.key,
97
- projectKey: projectInfo.key
98
- });
99
- }
100
- return jiraProjects;
88
+ if (!cachedProject) {
89
+ cache.set(key, projectInfo, { ttl: instance.cacheTtl });
90
+ }
91
+ return {
92
+ instance,
93
+ fullProjectKey: projectInfo.key,
94
+ projectKey: projectInfo.key
95
+ };
96
+ })
97
+ );
101
98
  }
102
99
  const getIssuesFromFilters = async (projectKeys, components, filters, instance, cache, jqlAnnotation) => {
103
100
  const projects = await getJiraProjectsFromKeys(projectKeys, instance, cache);
@@ -1 +1 @@
1
- {"version":3,"file":"service.cjs.js","sources":["../../src/service/service.ts"],"sourcesContent":["import { CacheService } from '@backstage/backend-plugin-api';\nimport {\n type Filter,\n Issue,\n type JiraDataResponse,\n type Project,\n} from '@axis-backstage/plugin-jira-dashboard-common';\nimport {\n getFilterById,\n getIssuesByComponent,\n getIssuesByFilter,\n getProjectInfo,\n searchJira,\n SearchOptions,\n} from '../api';\nimport { jqlQueryBuilder } from '../queries';\nimport type { ConfigInstance } from '../config';\nimport { JiraProject } from '../lib';\n\nexport const getProjectResponse = async (\n project: JiraProject,\n cache: CacheService,\n): Promise<Project> => {\n let projectResponse: Project;\n\n projectResponse = (await cache.get(project.fullProjectKey)) as Project;\n\n if (projectResponse) {\n return projectResponse as Project;\n }\n\n try {\n projectResponse = await getProjectInfo(project);\n cache.set(project.fullProjectKey, projectResponse, {\n ttl: project.instance.cacheTtl,\n });\n } catch (err: any) {\n if (err.message !== 200) {\n throw Error(\n `Failed to get project info for project key ${project.fullProjectKey} with error: ${err.message}`,\n );\n }\n }\n return projectResponse;\n};\n\nexport const getJqlResponse = async (\n jql: string,\n config: ConfigInstance,\n cache: CacheService,\n searchOptions: SearchOptions,\n): Promise<Issue[]> => {\n let issuesResponse: Issue[];\n\n const cacheKey = `${config.baseUrl} ${jql}`;\n\n issuesResponse = (await cache.get(cacheKey)) as Issue[];\n\n if (issuesResponse) {\n return issuesResponse;\n }\n\n try {\n issuesResponse = (await searchJira(config, jql, searchOptions)).issues;\n cache.set(cacheKey, issuesResponse, { ttl: config.cacheTtl });\n } catch (err: any) {\n if (err.message !== 200) {\n throw Error(\n `Failed to get issues for JQL ${jql} with error: ${err.message}`,\n );\n }\n }\n return issuesResponse;\n};\n\nexport const getUserIssues = async (\n username: string,\n maxResults: number,\n config: ConfigInstance,\n cache: CacheService,\n filterName: string,\n): Promise<Issue[]> => {\n let jql = `assignee = \"${username}\" AND resolution = Unresolved ORDER BY priority DESC, updated DESC`;\n if (filterName !== 'default') {\n for (const filter of config.defaultFilters || []) {\n if (filterName === filter.name) {\n jql = `assignee = \"${username}\" AND ${filter.query}`;\n }\n }\n }\n\n return getJqlResponse(jql, config, cache, {\n fields: [\n 'key',\n 'issuetype',\n 'summary',\n 'status',\n 'priority',\n 'created',\n 'updated',\n ],\n maxResults,\n });\n};\n\nexport const getFiltersFromAnnotations = async (\n annotations: string[],\n config: ConfigInstance,\n): Promise<Filter[]> => {\n const filters: Filter[] = [];\n\n for (const filter of annotations) {\n try {\n const response = await getFilterById(filter, config);\n filters.push(response);\n } catch (err: any) {\n console.warn(\n `${err.message} : Could not find filter with filter id ${filter}`,\n );\n }\n }\n return filters;\n};\nasync function getJiraProjectsFromKeys(\n projectKeys: string[],\n instance: ConfigInstance,\n cache: CacheService,\n): Promise<JiraProject[]> {\n const jiraProjects: JiraProject[] = [];\n for (const key of projectKeys) {\n const cachedProject = (await cache.get(key)) as Project;\n let projectInfo: Project;\n\n if (cachedProject) {\n projectInfo = cachedProject;\n } else {\n projectInfo = await getProjectInfo({\n projectKey: key,\n instance,\n fullProjectKey: '',\n });\n cache.set(key, projectInfo, { ttl: instance.cacheTtl });\n }\n\n jiraProjects.push({\n instance,\n fullProjectKey: projectInfo.key,\n projectKey: projectInfo.key,\n });\n }\n return jiraProjects;\n}\nexport const getIssuesFromFilters = async (\n projectKeys: string[],\n components: string[],\n filters: Filter[],\n instance: ConfigInstance,\n cache: CacheService,\n jqlAnnotation?: string,\n): Promise<JiraDataResponse[]> => {\n const projects = await getJiraProjectsFromKeys(projectKeys, instance, cache);\n return await Promise.all(\n filters.map(async filter => {\n const combinedQuery = `${jqlAnnotation ? `(${jqlAnnotation}) AND ` : ''}${\n filter.query\n }`;\n return {\n name: filter.name,\n query: jqlQueryBuilder({\n project: projectKeys,\n components,\n query: combinedQuery,\n }),\n type: 'filter',\n issues: await getIssuesByFilter(projects, components, combinedQuery),\n };\n }),\n );\n};\n\nexport const getIssuesFromComponents = async (\n projectKeys: string[],\n componentAnnotations: string[],\n instance: ConfigInstance,\n cache: CacheService,\n jqlAnnotation?: string,\n): Promise<JiraDataResponse[]> => {\n const projects = await getJiraProjectsFromKeys(projectKeys, instance, cache);\n return await Promise.all(\n componentAnnotations.map(async componentKey => ({\n name: componentKey,\n query: jqlQueryBuilder({\n project: projectKeys,\n components: [componentKey],\n query: jqlQueryBuilder({\n project: projectKeys,\n components: componentAnnotations,\n query: jqlAnnotation,\n }),\n }),\n type: 'component',\n issues: await getIssuesByComponent(projects, componentKey, jqlAnnotation),\n })),\n );\n};\n"],"names":["getProjectInfo","searchJira","getFilterById","jqlQueryBuilder","getIssuesByFilter","getIssuesByComponent"],"mappings":"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"}
1
+ {"version":3,"file":"service.cjs.js","sources":["../../src/service/service.ts"],"sourcesContent":["import { CacheService } from '@backstage/backend-plugin-api';\nimport {\n type Filter,\n Issue,\n type JiraDataResponse,\n type Project,\n} from '@axis-backstage/plugin-jira-dashboard-common';\nimport {\n getFilterById,\n getIssuesByComponent,\n getIssuesByFilter,\n getProjectInfo,\n searchJira,\n SearchOptions,\n} from '../api';\nimport { jqlQueryBuilder } from '../queries';\nimport type { ConfigInstance } from '../config';\nimport { JiraProject } from '../lib';\n\nexport const getProjectResponse = async (\n project: JiraProject,\n cache: CacheService,\n): Promise<Project> => {\n let projectResponse: Project;\n\n projectResponse = (await cache.get(project.fullProjectKey)) as Project;\n\n if (projectResponse) {\n return projectResponse as Project;\n }\n\n try {\n projectResponse = await getProjectInfo(project);\n cache.set(project.fullProjectKey, projectResponse, {\n ttl: project.instance.cacheTtl,\n });\n } catch (err: any) {\n if (err.message !== 200) {\n throw Error(\n `Failed to get project info for project key ${project.fullProjectKey} with error: ${err.message}`,\n );\n }\n }\n return projectResponse;\n};\n\nexport const getJqlResponse = async (\n jql: string,\n config: ConfigInstance,\n cache: CacheService,\n searchOptions: SearchOptions,\n): Promise<Issue[]> => {\n let issuesResponse: Issue[];\n\n const cacheKey = `${config.baseUrl} ${jql}`;\n\n issuesResponse = (await cache.get(cacheKey)) as Issue[];\n\n if (issuesResponse) {\n return issuesResponse;\n }\n\n try {\n issuesResponse = (await searchJira(config, jql, searchOptions)).issues;\n cache.set(cacheKey, issuesResponse, { ttl: config.cacheTtl });\n } catch (err: any) {\n if (err.message !== 200) {\n throw Error(\n `Failed to get issues for JQL ${jql} with error: ${err.message}`,\n );\n }\n }\n return issuesResponse;\n};\n\nexport const getUserIssues = async (\n username: string,\n maxResults: number,\n config: ConfigInstance,\n cache: CacheService,\n filterName: string,\n): Promise<Issue[]> => {\n let jql = `assignee = \"${username}\" AND resolution = Unresolved ORDER BY priority DESC, updated DESC`;\n if (filterName !== 'default') {\n for (const filter of config.defaultFilters || []) {\n if (filterName === filter.name) {\n jql = `assignee = \"${username}\" AND ${filter.query}`;\n }\n }\n }\n\n return getJqlResponse(jql, config, cache, {\n fields: [\n 'key',\n 'issuetype',\n 'summary',\n 'status',\n 'priority',\n 'created',\n 'updated',\n ],\n maxResults,\n });\n};\n\nexport const getFiltersFromAnnotations = async (\n annotations: string[],\n config: ConfigInstance,\n): Promise<Filter[]> => {\n const results = await Promise.allSettled(\n annotations.map(filter => getFilterById(filter, config)),\n );\n\n return results\n .map((result, i) => {\n if (result.status === 'rejected') {\n console.warn(\n `${result.reason.message} : Could not find filter with filter id ${annotations[i]}`,\n );\n return null;\n }\n return result.value;\n })\n .filter((filter): filter is Filter => filter !== null);\n};\nasync function getJiraProjectsFromKeys(\n projectKeys: string[],\n instance: ConfigInstance,\n cache: CacheService,\n): Promise<JiraProject[]> {\n return Promise.all(\n projectKeys.map(async key => {\n const cachedProject = (await cache.get(key)) as Project;\n const projectInfo =\n cachedProject ??\n (await getProjectInfo({\n projectKey: key,\n instance,\n fullProjectKey: '',\n }));\n\n if (!cachedProject) {\n cache.set(key, projectInfo, { ttl: instance.cacheTtl });\n }\n\n return {\n instance,\n fullProjectKey: projectInfo.key,\n projectKey: projectInfo.key,\n };\n }),\n );\n}\nexport const getIssuesFromFilters = async (\n projectKeys: string[],\n components: string[],\n filters: Filter[],\n instance: ConfigInstance,\n cache: CacheService,\n jqlAnnotation?: string,\n): Promise<JiraDataResponse[]> => {\n const projects = await getJiraProjectsFromKeys(projectKeys, instance, cache);\n return await Promise.all(\n filters.map(async filter => {\n const combinedQuery = `${jqlAnnotation ? `(${jqlAnnotation}) AND ` : ''}${\n filter.query\n }`;\n return {\n name: filter.name,\n query: jqlQueryBuilder({\n project: projectKeys,\n components,\n query: combinedQuery,\n }),\n type: 'filter',\n issues: await getIssuesByFilter(projects, components, combinedQuery),\n };\n }),\n );\n};\n\nexport const getIssuesFromComponents = async (\n projectKeys: string[],\n componentAnnotations: string[],\n instance: ConfigInstance,\n cache: CacheService,\n jqlAnnotation?: string,\n): Promise<JiraDataResponse[]> => {\n const projects = await getJiraProjectsFromKeys(projectKeys, instance, cache);\n return await Promise.all(\n componentAnnotations.map(async componentKey => ({\n name: componentKey,\n query: jqlQueryBuilder({\n project: projectKeys,\n components: [componentKey],\n query: jqlQueryBuilder({\n project: projectKeys,\n components: componentAnnotations,\n query: jqlAnnotation,\n }),\n }),\n type: 'component',\n issues: await getIssuesByComponent(projects, componentKey, jqlAnnotation),\n })),\n );\n};\n"],"names":["getProjectInfo","searchJira","getFilterById","jqlQueryBuilder","getIssuesByFilter","getIssuesByComponent"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-backstage/plugin-jira-dashboard-backend",
3
- "version": "6.1.0",
3
+ "version": "6.1.2",
4
4
  "main": "dist/index.cjs.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -33,8 +33,8 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@axis-backstage/plugin-jira-dashboard-common": "^1.15.0",
36
- "@backstage/backend-defaults": "^0.14.0",
37
- "@backstage/backend-plugin-api": "^1.6.0",
36
+ "@backstage/backend-defaults": "^0.15.1",
37
+ "@backstage/backend-plugin-api": "^1.6.2",
38
38
  "@backstage/catalog-client": "^1.12.1",
39
39
  "@backstage/catalog-model": "^1.7.6",
40
40
  "@backstage/config": "^1.3.6",
@@ -45,7 +45,7 @@
45
45
  "node-fetch": "^2.6.7"
46
46
  },
47
47
  "devDependencies": {
48
- "@backstage/backend-test-utils": "^1.10.2",
48
+ "@backstage/backend-test-utils": "^1.10.4",
49
49
  "@backstage/cli": "^0.35.1",
50
50
  "@backstage/plugin-auth-backend": "^0.25.7",
51
51
  "@backstage/plugin-auth-backend-module-guest-provider": "^0.2.15",