@backstage/catalog-client 0.5.2 → 0.5.5

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,34 @@
1
1
  # @backstage/catalog-client
2
2
 
3
+ ## 0.5.5
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @backstage/catalog-model@0.9.10
9
+
10
+ ## 0.5.5-next.0
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies
15
+ - @backstage/catalog-model@0.9.10-next.0
16
+
17
+ ## 0.5.4
18
+
19
+ ### Patch Changes
20
+
21
+ - Updated dependencies
22
+ - @backstage/errors@0.2.0
23
+ - @backstage/catalog-model@0.9.9
24
+
25
+ ## 0.5.3
26
+
27
+ ### Patch Changes
28
+
29
+ - 7927005152: Add the ability to supply a custom `fetchApi`. In the default frontend app setup, this will use the `fetchApiRef` implementation.
30
+ - 5463c03b35: Add support for passing paging parameters to the getEntities call of the catalog client
31
+
3
32
  ## 0.5.2
4
33
 
5
34
  ### Patch Changes
package/dist/index.cjs.js CHANGED
@@ -4,27 +4,28 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var catalogModel = require('@backstage/catalog-model');
6
6
  var errors = require('@backstage/errors');
7
- var fetch = require('cross-fetch');
7
+ var crossFetch = require('cross-fetch');
8
8
 
9
9
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
10
 
11
- var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
11
+ var crossFetch__default = /*#__PURE__*/_interopDefaultLegacy(crossFetch);
12
12
 
13
13
  const CATALOG_FILTER_EXISTS = Symbol("CATALOG_FILTER_EXISTS");
14
14
 
15
15
  class CatalogClient {
16
16
  constructor(options) {
17
17
  this.discoveryApi = options.discoveryApi;
18
+ this.fetchApi = options.fetchApi || { fetch: crossFetch__default["default"] };
18
19
  }
19
20
  async getEntityAncestors(request, options) {
20
- const {kind, namespace, name} = catalogModel.parseEntityRef(request.entityRef);
21
+ const { kind, namespace, name } = catalogModel.parseEntityRef(request.entityRef);
21
22
  return await this.requestRequired("GET", `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(namespace)}/${encodeURIComponent(name)}/ancestry`, options);
22
23
  }
23
24
  async getLocationById(id, options) {
24
25
  return await this.requestOptional("GET", `/locations/${encodeURIComponent(id)}`, options);
25
26
  }
26
27
  async getEntities(request, options) {
27
- const {filter = [], fields = []} = request != null ? request : {};
28
+ const { filter = [], fields = [], offset, limit, after } = request != null ? request : {};
28
29
  const filterItems = [filter].flat();
29
30
  const params = [];
30
31
  for (const filterItem of filterItems) {
@@ -45,6 +46,15 @@ class CatalogClient {
45
46
  if (fields.length) {
46
47
  params.push(`fields=${fields.map(encodeURIComponent).join(",")}`);
47
48
  }
49
+ if (offset !== void 0) {
50
+ params.push(`offset=${offset}`);
51
+ }
52
+ if (limit !== void 0) {
53
+ params.push(`limit=${limit}`);
54
+ }
55
+ if (after !== void 0) {
56
+ params.push(`after=${encodeURIComponent(after)}`);
57
+ }
48
58
  const query = params.length ? `?${params.join("&")}` : "";
49
59
  const entities = await this.requestRequired("GET", `/entities${query}`, options);
50
60
  const refCompare = (a, b) => {
@@ -62,38 +72,38 @@ class CatalogClient {
62
72
  }
63
73
  return 0;
64
74
  };
65
- return {items: entities.sort(refCompare)};
75
+ return { items: entities.sort(refCompare) };
66
76
  }
67
77
  async getEntityByName(compoundName, options) {
68
- const {kind, namespace = "default", name} = compoundName;
78
+ const { kind, namespace = "default", name } = compoundName;
69
79
  return this.requestOptional("GET", `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(namespace)}/${encodeURIComponent(name)}`, options);
70
80
  }
71
81
  async refreshEntity(entityRef, options) {
72
- const response = await fetch__default['default'](`${await this.discoveryApi.getBaseUrl("catalog")}/refresh`, {
82
+ const response = await this.fetchApi.fetch(`${await this.discoveryApi.getBaseUrl("catalog")}/refresh`, {
73
83
  headers: {
74
84
  "Content-Type": "application/json",
75
- ...(options == null ? void 0 : options.token) && {Authorization: `Bearer ${options == null ? void 0 : options.token}`}
85
+ ...(options == null ? void 0 : options.token) && { Authorization: `Bearer ${options == null ? void 0 : options.token}` }
76
86
  },
77
87
  method: "POST",
78
- body: JSON.stringify({entityRef})
88
+ body: JSON.stringify({ entityRef })
79
89
  });
80
90
  if (response.status !== 200) {
81
91
  throw new Error(await response.text());
82
92
  }
83
93
  }
84
- async addLocation({type = "url", target, dryRun, presence}, options) {
85
- const response = await fetch__default['default'](`${await this.discoveryApi.getBaseUrl("catalog")}/locations${dryRun ? "?dryRun=true" : ""}`, {
94
+ async addLocation({ type = "url", target, dryRun, presence }, options) {
95
+ const response = await this.fetchApi.fetch(`${await this.discoveryApi.getBaseUrl("catalog")}/locations${dryRun ? "?dryRun=true" : ""}`, {
86
96
  headers: {
87
97
  "Content-Type": "application/json",
88
- ...(options == null ? void 0 : options.token) && {Authorization: `Bearer ${options == null ? void 0 : options.token}`}
98
+ ...(options == null ? void 0 : options.token) && { Authorization: `Bearer ${options == null ? void 0 : options.token}` }
89
99
  },
90
100
  method: "POST",
91
- body: JSON.stringify({type, target, presence})
101
+ body: JSON.stringify({ type, target, presence })
92
102
  });
93
103
  if (response.status !== 201) {
94
104
  throw new Error(await response.text());
95
105
  }
96
- const {location, entities, exists} = await response.json();
106
+ const { location, entities, exists } = await response.json();
97
107
  if (!location) {
98
108
  throw new Error(`Location wasn't added: ${target}`);
99
109
  }
@@ -129,16 +139,16 @@ class CatalogClient {
129
139
  }
130
140
  async requestIgnored(method, path, options) {
131
141
  const url = `${await this.discoveryApi.getBaseUrl("catalog")}${path}`;
132
- const headers = (options == null ? void 0 : options.token) ? {Authorization: `Bearer ${options.token}`} : {};
133
- const response = await fetch__default['default'](url, {method, headers});
142
+ const headers = (options == null ? void 0 : options.token) ? { Authorization: `Bearer ${options.token}` } : {};
143
+ const response = await this.fetchApi.fetch(url, { method, headers });
134
144
  if (!response.ok) {
135
145
  throw await errors.ResponseError.fromResponse(response);
136
146
  }
137
147
  }
138
148
  async requestRequired(method, path, options) {
139
149
  const url = `${await this.discoveryApi.getBaseUrl("catalog")}${path}`;
140
- const headers = (options == null ? void 0 : options.token) ? {Authorization: `Bearer ${options.token}`} : {};
141
- const response = await fetch__default['default'](url, {method, headers});
150
+ const headers = (options == null ? void 0 : options.token) ? { Authorization: `Bearer ${options.token}` } : {};
151
+ const response = await this.fetchApi.fetch(url, { method, headers });
142
152
  if (!response.ok) {
143
153
  throw await errors.ResponseError.fromResponse(response);
144
154
  }
@@ -146,8 +156,8 @@ class CatalogClient {
146
156
  }
147
157
  async requestOptional(method, path, options) {
148
158
  const url = `${await this.discoveryApi.getBaseUrl("catalog")}${path}`;
149
- const headers = (options == null ? void 0 : options.token) ? {Authorization: `Bearer ${options.token}`} : {};
150
- const response = await fetch__default['default'](url, {method, headers});
159
+ const headers = (options == null ? void 0 : options.token) ? { Authorization: `Bearer ${options.token}` } : {};
160
+ const response = await this.fetchApi.fetch(url, { method, headers });
151
161
  if (!response.ok) {
152
162
  if (response.status === 404) {
153
163
  return void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/types/api.ts","../src/CatalogClient.ts","../src/types/status.ts"],"sourcesContent":["/*\n * Copyright 2021 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 */\n\nimport { Entity, EntityName, Location } from '@backstage/catalog-model';\n\n/**\n * A Symbol to define if a catalog filter exists or not.\n *\n * @public\n */\nexport const CATALOG_FILTER_EXISTS = Symbol('CATALOG_FILTER_EXISTS');\n\n/**\n * A request type for retrieving catalog Entities.\n *\n * @public\n */\nexport type CatalogEntitiesRequest = {\n filter?:\n | Record<string, string | symbol | (string | symbol)[]>[]\n | Record<string, string | symbol | (string | symbol)[]>\n | undefined;\n fields?: string[] | undefined;\n};\n\n/**\n * A request type for Catalog Entity Ancestor information.\n *\n * @public\n */\nexport type CatalogEntityAncestorsRequest = {\n entityRef: string;\n};\n\n/**\n * A response type for Catalog Entity Ancestor information.\n *\n * @public\n */\nexport type CatalogEntityAncestorsResponse = {\n root: EntityName;\n items: { entity: Entity; parents: EntityName[] }[];\n};\n\n/**\n * A response type for the result of a catalog operation in list form.\n *\n * @public\n */\nexport type CatalogListResponse<T> = {\n items: T[];\n};\n\n/**\n * Options you can pass into a catalog request for additional information.\n *\n * @public\n */\nexport type CatalogRequestOptions = {\n token?: string;\n};\n\n/**\n * Public functions for interacting with the Catalog API.\n *\n * @public\n */\nexport interface CatalogApi {\n /**\n * Gets the Entities from the catalog based on your request and options.\n *\n * @param request - An object with your filters and fields.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogListResponse with items typed Catalog Model Entity.\n *\n */\n getEntities(\n request?: CatalogEntitiesRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogListResponse<Entity>>;\n /**\n * Gets the Entity ancestor information from the catalog based on your request and options.\n *\n * @param request - An object with your filters and fields.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogEntityAncestorsResponse.\n */\n getEntityAncestors(\n request: CatalogEntityAncestorsRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogEntityAncestorsResponse>;\n /**\n * Gets a single Entity from the catalog by Entity name.\n *\n * @param name - A complete Entity name, with the full kind-namespace-name triplet.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Entity}.\n */\n getEntityByName(\n name: EntityName,\n options?: CatalogRequestOptions,\n ): Promise<Entity | undefined>;\n /**\n * Removes a single Entity from the catalog by Entity UID.\n *\n * @param uid - A string of the Entity UID.\n * @param options - An object with your preferred options.\n *\n */\n removeEntityByUid(\n uid: string,\n options?: CatalogRequestOptions,\n ): Promise<void>;\n /**\n * Refreshes an Entity in the catalog.\n *\n * @param entityRef - A string in the form of 'Kind/default:foo'.\n * @param options - An object with your preferred options.\n *\n */\n refreshEntity(\n entityRef: string,\n options?: CatalogRequestOptions,\n ): Promise<void>;\n\n // Locations\n /**\n * Gets a Location object by ID from the catalog.\n *\n * @param id - A string in of the Location Id.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n */\n getLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined>;\n /**\n * Gets origin location by Entity.\n *\n * @param entity - An {@link catalog-model#Entity}.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n */\n getOriginLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined>;\n /**\n * Gets Location by Entity.\n *\n * @param entity - An {@link catalog-model#Entity}.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n */\n getLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined>;\n /**\n * Adds a Location.\n *\n * @param location - A request type for adding a Location to the catalog.\n * @param options - An object with your preferred options.\n *\n * @returns A AddLocationResponse.\n */\n addLocation(\n location: AddLocationRequest,\n options?: CatalogRequestOptions,\n ): Promise<AddLocationResponse>;\n /**\n * Removes a Location by Id.\n *\n * @param id - A string in of the Location Id.\n * @param options - An object with your preferred options.\n *\n */\n removeLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<void>;\n}\n\n/**\n * A request type for adding a Location to the catalog.\n *\n * @public\n */\nexport type AddLocationRequest = {\n type?: string;\n target: string;\n dryRun?: boolean;\n presence?: 'optional' | 'required';\n};\n\n/**\n * A response type for adding a Location to the catalog.\n *\n * @public\n */\nexport type AddLocationResponse = {\n location: Location;\n entities: Entity[];\n // Exists is only set in DryRun mode.\n exists?: boolean;\n};\n","/*\n * Copyright 2020 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 */\n\nimport {\n Entity,\n EntityName,\n Location,\n LOCATION_ANNOTATION,\n ORIGIN_LOCATION_ANNOTATION,\n parseEntityRef,\n stringifyEntityRef,\n stringifyLocationReference,\n} from '@backstage/catalog-model';\nimport { ResponseError } from '@backstage/errors';\nimport fetch from 'cross-fetch';\nimport {\n CATALOG_FILTER_EXISTS,\n AddLocationRequest,\n AddLocationResponse,\n CatalogApi,\n CatalogEntitiesRequest,\n CatalogListResponse,\n CatalogRequestOptions,\n CatalogEntityAncestorsRequest,\n CatalogEntityAncestorsResponse,\n} from './types/api';\nimport { DiscoveryApi } from './types/discovery';\n\n/**\n * A frontend and backend compatible client for communicating with the Backstage Catalog.\n *\n * @public\n * */\nexport class CatalogClient implements CatalogApi {\n private readonly discoveryApi: DiscoveryApi;\n\n constructor(options: { discoveryApi: DiscoveryApi }) {\n this.discoveryApi = options.discoveryApi;\n }\n\n /**\n * Gets the Ancestors of an Entity.\n *\n * @param request - A request type for retrieving Entity ancestors.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogEntityAncestorsResponse.\n *\n * @public\n */\n async getEntityAncestors(\n request: CatalogEntityAncestorsRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogEntityAncestorsResponse> {\n const { kind, namespace, name } = parseEntityRef(request.entityRef);\n return await this.requestRequired(\n 'GET',\n `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(\n namespace,\n )}/${encodeURIComponent(name)}/ancestry`,\n options,\n );\n }\n\n /**\n * Gets a Location by Id.\n *\n * @param id - A string containing the Id.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n return await this.requestOptional(\n 'GET',\n `/locations/${encodeURIComponent(id)}`,\n options,\n );\n }\n\n /**\n * Gets a set of Entities.\n *\n * @param request - A request type for retrieving an Entity.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogListResponse.\n *\n * @public\n */\n async getEntities(\n request?: CatalogEntitiesRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogListResponse<Entity>> {\n const { filter = [], fields = [] } = request ?? {};\n const filterItems = [filter].flat();\n const params: string[] = [];\n\n // filter param can occur multiple times, for example\n // /api/catalog/entities?filter=metadata.name=wayback-search,kind=component&filter=metadata.name=www-artist,kind=component'\n // the \"outer array\" defined by `filter` occurrences corresponds to \"anyOf\" filters\n // the \"inner array\" defined within a `filter` param corresponds to \"allOf\" filters\n for (const filterItem of filterItems) {\n const filterParts: string[] = [];\n for (const [key, value] of Object.entries(filterItem)) {\n for (const v of [value].flat()) {\n if (v === CATALOG_FILTER_EXISTS) {\n filterParts.push(encodeURIComponent(key));\n } else if (typeof v === 'string') {\n filterParts.push(\n `${encodeURIComponent(key)}=${encodeURIComponent(v)}`,\n );\n }\n }\n }\n\n if (filterParts.length) {\n params.push(`filter=${filterParts.join(',')}`);\n }\n }\n\n if (fields.length) {\n params.push(`fields=${fields.map(encodeURIComponent).join(',')}`);\n }\n\n const query = params.length ? `?${params.join('&')}` : '';\n const entities: Entity[] = await this.requestRequired(\n 'GET',\n `/entities${query}`,\n options,\n );\n\n const refCompare = (a: Entity, b: Entity) => {\n // in case field filtering is used, these fields might not be part of the response\n if (\n a.metadata?.name === undefined ||\n a.kind === undefined ||\n b.metadata?.name === undefined ||\n b.kind === undefined\n ) {\n return 0;\n }\n\n const aRef = stringifyEntityRef(a);\n const bRef = stringifyEntityRef(b);\n if (aRef < bRef) {\n return -1;\n }\n if (aRef > bRef) {\n return 1;\n }\n return 0;\n };\n\n return { items: entities.sort(refCompare) };\n }\n\n /**\n * Gets a given Entity based on a provided name.\n *\n * @param compoundName - A string containing the name.\n * @param options - An object with your preferred options.\n *\n * @returns An {@link catalog-model#Entity}.\n *\n * @public\n */\n async getEntityByName(\n compoundName: EntityName,\n options?: CatalogRequestOptions,\n ): Promise<Entity | undefined> {\n const { kind, namespace = 'default', name } = compoundName;\n return this.requestOptional(\n 'GET',\n `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(\n namespace,\n )}/${encodeURIComponent(name)}`,\n options,\n );\n }\n\n /**\n * Refreshes an Entity.\n *\n * @param entityRef - A string containing the entityREf\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async refreshEntity(entityRef: string, options?: CatalogRequestOptions) {\n const response = await fetch(\n `${await this.discoveryApi.getBaseUrl('catalog')}/refresh`,\n {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'POST',\n body: JSON.stringify({ entityRef }),\n },\n );\n\n if (response.status !== 200) {\n throw new Error(await response.text());\n }\n }\n\n /**\n * Adds a location.\n *\n * @param options - An object with your preferred options.\n * @param AddLocationRequest - A request object for adding locations.\n *\n * @returns An AddLocationResponse\n *\n * @public\n */\n async addLocation(\n { type = 'url', target, dryRun, presence }: AddLocationRequest,\n options?: CatalogRequestOptions,\n ): Promise<AddLocationResponse> {\n const response = await fetch(\n `${await this.discoveryApi.getBaseUrl('catalog')}/locations${\n dryRun ? '?dryRun=true' : ''\n }`,\n {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'POST',\n body: JSON.stringify({ type, target, presence }),\n },\n );\n\n if (response.status !== 201) {\n throw new Error(await response.text());\n }\n\n const { location, entities, exists } = await response.json();\n\n if (!location) {\n throw new Error(`Location wasn't added: ${target}`);\n }\n\n return {\n location,\n entities,\n exists,\n };\n }\n\n /**\n * Gets an origin Location By Entity.\n *\n * @param entity - An Entity\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getOriginLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n const locationCompound =\n entity.metadata.annotations?.[ORIGIN_LOCATION_ANNOTATION];\n if (!locationCompound) {\n return undefined;\n }\n const all: { data: Location }[] = await this.requestRequired(\n 'GET',\n '/locations',\n options,\n );\n return all\n .map(r => r.data)\n .find(l => locationCompound === stringifyLocationReference(l));\n }\n\n /**\n * Gets a Location by Entity.\n *\n * @param entity - An Entity\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n const locationCompound = entity.metadata.annotations?.[LOCATION_ANNOTATION];\n if (!locationCompound) {\n return undefined;\n }\n const all: { data: Location }[] = await this.requestRequired(\n 'GET',\n '/locations',\n options,\n );\n return all\n .map(r => r.data)\n .find(l => locationCompound === stringifyLocationReference(l));\n }\n\n /**\n * Removes a location as identified by Id.\n *\n * @param id - A string containing the Id\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async removeLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n await this.requestIgnored(\n 'DELETE',\n `/locations/${encodeURIComponent(id)}`,\n options,\n );\n }\n\n /**\n * Removes an Entity as identified by Uid.\n *\n * @param uid - A string containing the Uid\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async removeEntityByUid(\n uid: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n await this.requestIgnored(\n 'DELETE',\n `/entities/by-uid/${encodeURIComponent(uid)}`,\n options,\n );\n }\n\n //\n // Private methods\n //\n\n private async requestIgnored(\n method: string,\n path: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers: Record<string, string> = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await fetch(url, { method, headers });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n }\n\n private async requestRequired(\n method: string,\n path: string,\n options?: CatalogRequestOptions,\n ): Promise<any> {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers: Record<string, string> = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await fetch(url, { method, headers });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n\n private async requestOptional(\n method: string,\n path: string,\n options?: CatalogRequestOptions,\n ): Promise<any | undefined> {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers: Record<string, string> = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await fetch(url, { method, headers });\n\n if (!response.ok) {\n if (response.status === 404) {\n return undefined;\n }\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n}\n","/*\n * Copyright 2021 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 */\n\n/**\n * The entity `status.items[].type` for the status of the processing engine in\n * regards to an entity.\n *\n * @public\n */\nexport const ENTITY_STATUS_CATALOG_PROCESSING_TYPE =\n 'backstage.io/catalog-processing';\n"],"names":["parseEntityRef","stringifyEntityRef","fetch","ORIGIN_LOCATION_ANNOTATION","stringifyLocationReference","LOCATION_ANNOTATION","ResponseError"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/types/api.ts","../src/CatalogClient.ts","../src/types/status.ts"],"sourcesContent":["/*\n * Copyright 2021 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 */\n\nimport { Entity, EntityName, Location } from '@backstage/catalog-model';\n\n/**\n * A Symbol to define if a catalog filter exists or not.\n *\n * @public\n */\nexport const CATALOG_FILTER_EXISTS = Symbol('CATALOG_FILTER_EXISTS');\n\n/**\n * A request type for retrieving catalog Entities.\n *\n * @public\n */\nexport type CatalogEntitiesRequest = {\n /**\n * If given, return only entities that match the given patterns.\n *\n * @remarks\n *\n * If multiple filter sets are given as an array, then there is effectively an\n * OR between each filter set.\n *\n * Within one filter set, there is effectively an AND between the various\n * keys.\n *\n * Within one key, if there are more than one value, then there is effectively\n * an OR between them.\n *\n * Example: For an input of\n *\n * ```\n * [\n * { kind: ['API', 'Component'] },\n * { 'metadata.name': 'a', 'metadata.namespace': 'b' }\n * ]\n * ```\n *\n * This effectively means\n *\n * ```\n * (kind = EITHER 'API' OR 'Component')\n * OR\n * (metadata.name = 'a' AND metadata.namespace = 'b' )\n * ```\n *\n * Each key is a dot separated path in each object.\n *\n * As a value you can also pass in the symbol `CATALOG_FILTER_EXISTS`\n * (exported from this package), which means that you assert on the existence\n * of that key, no matter what its value is.\n */\n filter?:\n | Record<string, string | symbol | (string | symbol)[]>[]\n | Record<string, string | symbol | (string | symbol)[]>\n | undefined;\n /**\n * If given, return only the parts of each entity that match those dot\n * separated paths in each object.\n *\n * @remarks\n *\n * Example: For an input of `['kind', 'metadata.annotations']`, then response\n * objects will be shaped like\n *\n * ```\n * {\n * \"kind\": \"Component\",\n * \"metadata\": {\n * \"annotations\": {\n * \"foo\": \"bar\"\n * }\n * }\n * }\n * ```\n */\n fields?: string[] | undefined;\n /**\n * If given, skips over the first N items in the result set.\n */\n offset?: number;\n /**\n * If given, returns at most N items from the result set.\n */\n limit?: number;\n /**\n * If given, skips over all items before that cursor as returned by a previous\n * request.\n */\n after?: string;\n};\n\n/**\n * A request type for Catalog Entity Ancestor information.\n *\n * @public\n */\nexport type CatalogEntityAncestorsRequest = {\n entityRef: string;\n};\n\n/**\n * A response type for Catalog Entity Ancestor information.\n *\n * @public\n */\nexport type CatalogEntityAncestorsResponse = {\n root: EntityName;\n items: { entity: Entity; parents: EntityName[] }[];\n};\n\n/**\n * A response type for the result of a catalog operation in list form.\n *\n * @public\n */\nexport type CatalogListResponse<T> = {\n items: T[];\n};\n\n/**\n * Options you can pass into a catalog request for additional information.\n *\n * @public\n */\nexport type CatalogRequestOptions = {\n token?: string;\n};\n\n/**\n * Public functions for interacting with the Catalog API.\n *\n * @public\n */\nexport interface CatalogApi {\n /**\n * Gets the Entities from the catalog based on your request and options.\n *\n * @param request - An object with your filters and fields.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogListResponse with items typed Catalog Model Entity.\n *\n */\n getEntities(\n request?: CatalogEntitiesRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogListResponse<Entity>>;\n /**\n * Gets the Entity ancestor information from the catalog based on your request and options.\n *\n * @param request - An object with your filters and fields.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogEntityAncestorsResponse.\n */\n getEntityAncestors(\n request: CatalogEntityAncestorsRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogEntityAncestorsResponse>;\n /**\n * Gets a single Entity from the catalog by Entity name.\n *\n * @param name - A complete Entity name, with the full kind-namespace-name triplet.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Entity}.\n */\n getEntityByName(\n name: EntityName,\n options?: CatalogRequestOptions,\n ): Promise<Entity | undefined>;\n /**\n * Removes a single Entity from the catalog by Entity UID.\n *\n * @param uid - A string of the Entity UID.\n * @param options - An object with your preferred options.\n *\n */\n removeEntityByUid(\n uid: string,\n options?: CatalogRequestOptions,\n ): Promise<void>;\n /**\n * Refreshes an Entity in the catalog.\n *\n * @param entityRef - A string in the form of 'Kind/default:foo'.\n * @param options - An object with your preferred options.\n *\n */\n refreshEntity(\n entityRef: string,\n options?: CatalogRequestOptions,\n ): Promise<void>;\n\n // Locations\n /**\n * Gets a Location object by ID from the catalog.\n *\n * @param id - A string in of the Location Id.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n */\n getLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined>;\n /**\n * Gets origin location by Entity.\n *\n * @param entity - An {@link catalog-model#Entity}.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n */\n getOriginLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined>;\n /**\n * Gets Location by Entity.\n *\n * @param entity - An {@link catalog-model#Entity}.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n */\n getLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined>;\n /**\n * Adds a Location.\n *\n * @param location - A request type for adding a Location to the catalog.\n * @param options - An object with your preferred options.\n *\n * @returns A AddLocationResponse.\n */\n addLocation(\n location: AddLocationRequest,\n options?: CatalogRequestOptions,\n ): Promise<AddLocationResponse>;\n /**\n * Removes a Location by Id.\n *\n * @param id - A string in of the Location Id.\n * @param options - An object with your preferred options.\n *\n */\n removeLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<void>;\n}\n\n/**\n * A request type for adding a Location to the catalog.\n *\n * @public\n */\nexport type AddLocationRequest = {\n type?: string;\n target: string;\n dryRun?: boolean;\n presence?: 'optional' | 'required';\n};\n\n/**\n * A response type for adding a Location to the catalog.\n *\n * @public\n */\nexport type AddLocationResponse = {\n location: Location;\n entities: Entity[];\n // Exists is only set in DryRun mode.\n exists?: boolean;\n};\n","/*\n * Copyright 2020 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 */\n\nimport {\n Entity,\n EntityName,\n Location,\n LOCATION_ANNOTATION,\n ORIGIN_LOCATION_ANNOTATION,\n parseEntityRef,\n stringifyEntityRef,\n stringifyLocationReference,\n} from '@backstage/catalog-model';\nimport { ResponseError } from '@backstage/errors';\nimport crossFetch from 'cross-fetch';\nimport {\n CATALOG_FILTER_EXISTS,\n AddLocationRequest,\n AddLocationResponse,\n CatalogApi,\n CatalogEntitiesRequest,\n CatalogListResponse,\n CatalogRequestOptions,\n CatalogEntityAncestorsRequest,\n CatalogEntityAncestorsResponse,\n} from './types/api';\nimport { DiscoveryApi } from './types/discovery';\nimport { FetchApi } from './types/fetch';\n\n/**\n * A frontend and backend compatible client for communicating with the Backstage Catalog.\n *\n * @public\n * */\nexport class CatalogClient implements CatalogApi {\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 /**\n * Gets the Ancestors of an Entity.\n *\n * @param request - A request type for retrieving Entity ancestors.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogEntityAncestorsResponse.\n *\n * @public\n */\n async getEntityAncestors(\n request: CatalogEntityAncestorsRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogEntityAncestorsResponse> {\n const { kind, namespace, name } = parseEntityRef(request.entityRef);\n return await this.requestRequired(\n 'GET',\n `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(\n namespace,\n )}/${encodeURIComponent(name)}/ancestry`,\n options,\n );\n }\n\n /**\n * Gets a Location by Id.\n *\n * @param id - A string containing the Id.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n return await this.requestOptional(\n 'GET',\n `/locations/${encodeURIComponent(id)}`,\n options,\n );\n }\n\n /**\n * Gets a set of Entities.\n *\n * @param request - A request type for retrieving an Entity.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogListResponse.\n *\n * @public\n */\n async getEntities(\n request?: CatalogEntitiesRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogListResponse<Entity>> {\n const { filter = [], fields = [], offset, limit, after } = request ?? {};\n const filterItems = [filter].flat();\n const params: string[] = [];\n\n // filter param can occur multiple times, for example\n // /api/catalog/entities?filter=metadata.name=wayback-search,kind=component&filter=metadata.name=www-artist,kind=component'\n // the \"outer array\" defined by `filter` occurrences corresponds to \"anyOf\" filters\n // the \"inner array\" defined within a `filter` param corresponds to \"allOf\" filters\n for (const filterItem of filterItems) {\n const filterParts: string[] = [];\n for (const [key, value] of Object.entries(filterItem)) {\n for (const v of [value].flat()) {\n if (v === CATALOG_FILTER_EXISTS) {\n filterParts.push(encodeURIComponent(key));\n } else if (typeof v === 'string') {\n filterParts.push(\n `${encodeURIComponent(key)}=${encodeURIComponent(v)}`,\n );\n }\n }\n }\n\n if (filterParts.length) {\n params.push(`filter=${filterParts.join(',')}`);\n }\n }\n\n if (fields.length) {\n params.push(`fields=${fields.map(encodeURIComponent).join(',')}`);\n }\n\n if (offset !== undefined) {\n params.push(`offset=${offset}`);\n }\n if (limit !== undefined) {\n params.push(`limit=${limit}`);\n }\n if (after !== undefined) {\n params.push(`after=${encodeURIComponent(after)}`);\n }\n\n const query = params.length ? `?${params.join('&')}` : '';\n const entities: Entity[] = await this.requestRequired(\n 'GET',\n `/entities${query}`,\n options,\n );\n\n const refCompare = (a: Entity, b: Entity) => {\n // in case field filtering is used, these fields might not be part of the response\n if (\n a.metadata?.name === undefined ||\n a.kind === undefined ||\n b.metadata?.name === undefined ||\n b.kind === undefined\n ) {\n return 0;\n }\n\n const aRef = stringifyEntityRef(a);\n const bRef = stringifyEntityRef(b);\n if (aRef < bRef) {\n return -1;\n }\n if (aRef > bRef) {\n return 1;\n }\n return 0;\n };\n\n return { items: entities.sort(refCompare) };\n }\n\n /**\n * Gets a given Entity based on a provided name.\n *\n * @param compoundName - A string containing the name.\n * @param options - An object with your preferred options.\n *\n * @returns An {@link catalog-model#Entity}.\n *\n * @public\n */\n async getEntityByName(\n compoundName: EntityName,\n options?: CatalogRequestOptions,\n ): Promise<Entity | undefined> {\n const { kind, namespace = 'default', name } = compoundName;\n return this.requestOptional(\n 'GET',\n `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(\n namespace,\n )}/${encodeURIComponent(name)}`,\n options,\n );\n }\n\n /**\n * Refreshes an Entity.\n *\n * @param entityRef - A string containing the entityREf\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async refreshEntity(entityRef: string, options?: CatalogRequestOptions) {\n const response = await this.fetchApi.fetch(\n `${await this.discoveryApi.getBaseUrl('catalog')}/refresh`,\n {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'POST',\n body: JSON.stringify({ entityRef }),\n },\n );\n\n if (response.status !== 200) {\n throw new Error(await response.text());\n }\n }\n\n /**\n * Adds a location.\n *\n * @param options - An object with your preferred options.\n * @param AddLocationRequest - A request object for adding locations.\n *\n * @returns An AddLocationResponse\n *\n * @public\n */\n async addLocation(\n { type = 'url', target, dryRun, presence }: AddLocationRequest,\n options?: CatalogRequestOptions,\n ): Promise<AddLocationResponse> {\n const response = await this.fetchApi.fetch(\n `${await this.discoveryApi.getBaseUrl('catalog')}/locations${\n dryRun ? '?dryRun=true' : ''\n }`,\n {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'POST',\n body: JSON.stringify({ type, target, presence }),\n },\n );\n\n if (response.status !== 201) {\n throw new Error(await response.text());\n }\n\n const { location, entities, exists } = await response.json();\n\n if (!location) {\n throw new Error(`Location wasn't added: ${target}`);\n }\n\n return {\n location,\n entities,\n exists,\n };\n }\n\n /**\n * Gets an origin Location By Entity.\n *\n * @param entity - An Entity\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getOriginLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n const locationCompound =\n entity.metadata.annotations?.[ORIGIN_LOCATION_ANNOTATION];\n if (!locationCompound) {\n return undefined;\n }\n const all: { data: Location }[] = await this.requestRequired(\n 'GET',\n '/locations',\n options,\n );\n return all\n .map(r => r.data)\n .find(l => locationCompound === stringifyLocationReference(l));\n }\n\n /**\n * Gets a Location by Entity.\n *\n * @param entity - An Entity\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n const locationCompound = entity.metadata.annotations?.[LOCATION_ANNOTATION];\n if (!locationCompound) {\n return undefined;\n }\n const all: { data: Location }[] = await this.requestRequired(\n 'GET',\n '/locations',\n options,\n );\n return all\n .map(r => r.data)\n .find(l => locationCompound === stringifyLocationReference(l));\n }\n\n /**\n * Removes a location as identified by Id.\n *\n * @param id - A string containing the Id\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async removeLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n await this.requestIgnored(\n 'DELETE',\n `/locations/${encodeURIComponent(id)}`,\n options,\n );\n }\n\n /**\n * Removes an Entity as identified by Uid.\n *\n * @param uid - A string containing the Uid\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async removeEntityByUid(\n uid: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n await this.requestIgnored(\n 'DELETE',\n `/entities/by-uid/${encodeURIComponent(uid)}`,\n options,\n );\n }\n\n //\n // Private methods\n //\n\n private async requestIgnored(\n method: string,\n path: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers: Record<string, string> = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await this.fetchApi.fetch(url, { method, headers });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n }\n\n private async requestRequired(\n method: string,\n path: string,\n options?: CatalogRequestOptions,\n ): Promise<any> {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers: Record<string, string> = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await this.fetchApi.fetch(url, { method, headers });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n\n private async requestOptional(\n method: string,\n path: string,\n options?: CatalogRequestOptions,\n ): Promise<any | undefined> {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers: Record<string, string> = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await this.fetchApi.fetch(url, { method, headers });\n\n if (!response.ok) {\n if (response.status === 404) {\n return undefined;\n }\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n}\n","/*\n * Copyright 2021 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 */\n\n/**\n * The entity `status.items[].type` for the status of the processing engine in\n * regards to an entity.\n *\n * @public\n */\nexport const ENTITY_STATUS_CATALOG_PROCESSING_TYPE =\n 'backstage.io/catalog-processing';\n"],"names":["crossFetch","parseEntityRef","stringifyEntityRef","ORIGIN_LOCATION_ANNOTATION","stringifyLocationReference","LOCATION_ANNOTATION","ResponseError"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -12,8 +12,78 @@ declare const CATALOG_FILTER_EXISTS: unique symbol;
12
12
  * @public
13
13
  */
14
14
  declare type CatalogEntitiesRequest = {
15
+ /**
16
+ * If given, return only entities that match the given patterns.
17
+ *
18
+ * @remarks
19
+ *
20
+ * If multiple filter sets are given as an array, then there is effectively an
21
+ * OR between each filter set.
22
+ *
23
+ * Within one filter set, there is effectively an AND between the various
24
+ * keys.
25
+ *
26
+ * Within one key, if there are more than one value, then there is effectively
27
+ * an OR between them.
28
+ *
29
+ * Example: For an input of
30
+ *
31
+ * ```
32
+ * [
33
+ * { kind: ['API', 'Component'] },
34
+ * { 'metadata.name': 'a', 'metadata.namespace': 'b' }
35
+ * ]
36
+ * ```
37
+ *
38
+ * This effectively means
39
+ *
40
+ * ```
41
+ * (kind = EITHER 'API' OR 'Component')
42
+ * OR
43
+ * (metadata.name = 'a' AND metadata.namespace = 'b' )
44
+ * ```
45
+ *
46
+ * Each key is a dot separated path in each object.
47
+ *
48
+ * As a value you can also pass in the symbol `CATALOG_FILTER_EXISTS`
49
+ * (exported from this package), which means that you assert on the existence
50
+ * of that key, no matter what its value is.
51
+ */
15
52
  filter?: Record<string, string | symbol | (string | symbol)[]>[] | Record<string, string | symbol | (string | symbol)[]> | undefined;
53
+ /**
54
+ * If given, return only the parts of each entity that match those dot
55
+ * separated paths in each object.
56
+ *
57
+ * @remarks
58
+ *
59
+ * Example: For an input of `['kind', 'metadata.annotations']`, then response
60
+ * objects will be shaped like
61
+ *
62
+ * ```
63
+ * {
64
+ * "kind": "Component",
65
+ * "metadata": {
66
+ * "annotations": {
67
+ * "foo": "bar"
68
+ * }
69
+ * }
70
+ * }
71
+ * ```
72
+ */
16
73
  fields?: string[] | undefined;
74
+ /**
75
+ * If given, skips over the first N items in the result set.
76
+ */
77
+ offset?: number;
78
+ /**
79
+ * If given, returns at most N items from the result set.
80
+ */
81
+ limit?: number;
82
+ /**
83
+ * If given, skips over all items before that cursor as returned by a previous
84
+ * request.
85
+ */
86
+ after?: string;
17
87
  };
18
88
  /**
19
89
  * A request type for Catalog Entity Ancestor information.
@@ -169,7 +239,7 @@ declare type AddLocationResponse = {
169
239
  };
170
240
 
171
241
  /**
172
- * This is a copy of the core DiscoveryApi, to avoid importing core.
242
+ * This is a copy of the DiscoveryApi, to avoid importing core-plugin-api.
173
243
  *
174
244
  * @public
175
245
  */
@@ -177,6 +247,15 @@ declare type DiscoveryApi = {
177
247
  getBaseUrl(pluginId: string): Promise<string>;
178
248
  };
179
249
 
250
+ /**
251
+ * This is a copy of FetchApi, to avoid importing core-plugin-api.
252
+ *
253
+ * @public
254
+ */
255
+ declare type FetchApi = {
256
+ fetch: typeof fetch;
257
+ };
258
+
180
259
  /**
181
260
  * A frontend and backend compatible client for communicating with the Backstage Catalog.
182
261
  *
@@ -184,8 +263,10 @@ declare type DiscoveryApi = {
184
263
  * */
185
264
  declare class CatalogClient implements CatalogApi {
186
265
  private readonly discoveryApi;
266
+ private readonly fetchApi;
187
267
  constructor(options: {
188
268
  discoveryApi: DiscoveryApi;
269
+ fetchApi?: FetchApi;
189
270
  });
190
271
  /**
191
272
  * Gets the Ancestors of an Entity.
@@ -304,4 +385,4 @@ declare class CatalogClient implements CatalogApi {
304
385
  */
305
386
  declare const ENTITY_STATUS_CATALOG_PROCESSING_TYPE = "backstage.io/catalog-processing";
306
387
 
307
- export { AddLocationRequest, AddLocationResponse, CATALOG_FILTER_EXISTS, CatalogApi, CatalogClient, CatalogEntitiesRequest, CatalogEntityAncestorsRequest, CatalogEntityAncestorsResponse, CatalogListResponse, CatalogRequestOptions, DiscoveryApi, ENTITY_STATUS_CATALOG_PROCESSING_TYPE };
388
+ export { AddLocationRequest, AddLocationResponse, CATALOG_FILTER_EXISTS, CatalogApi, CatalogClient, CatalogEntitiesRequest, CatalogEntityAncestorsRequest, CatalogEntityAncestorsResponse, CatalogListResponse, CatalogRequestOptions, DiscoveryApi, ENTITY_STATUS_CATALOG_PROCESSING_TYPE, FetchApi };
package/dist/index.esm.js CHANGED
@@ -1,22 +1,23 @@
1
1
  import { parseEntityRef, ORIGIN_LOCATION_ANNOTATION, stringifyLocationReference, LOCATION_ANNOTATION, stringifyEntityRef } from '@backstage/catalog-model';
2
2
  import { ResponseError } from '@backstage/errors';
3
- import fetch from 'cross-fetch';
3
+ import crossFetch from 'cross-fetch';
4
4
 
5
5
  const CATALOG_FILTER_EXISTS = Symbol("CATALOG_FILTER_EXISTS");
6
6
 
7
7
  class CatalogClient {
8
8
  constructor(options) {
9
9
  this.discoveryApi = options.discoveryApi;
10
+ this.fetchApi = options.fetchApi || { fetch: crossFetch };
10
11
  }
11
12
  async getEntityAncestors(request, options) {
12
- const {kind, namespace, name} = parseEntityRef(request.entityRef);
13
+ const { kind, namespace, name } = parseEntityRef(request.entityRef);
13
14
  return await this.requestRequired("GET", `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(namespace)}/${encodeURIComponent(name)}/ancestry`, options);
14
15
  }
15
16
  async getLocationById(id, options) {
16
17
  return await this.requestOptional("GET", `/locations/${encodeURIComponent(id)}`, options);
17
18
  }
18
19
  async getEntities(request, options) {
19
- const {filter = [], fields = []} = request != null ? request : {};
20
+ const { filter = [], fields = [], offset, limit, after } = request != null ? request : {};
20
21
  const filterItems = [filter].flat();
21
22
  const params = [];
22
23
  for (const filterItem of filterItems) {
@@ -37,6 +38,15 @@ class CatalogClient {
37
38
  if (fields.length) {
38
39
  params.push(`fields=${fields.map(encodeURIComponent).join(",")}`);
39
40
  }
41
+ if (offset !== void 0) {
42
+ params.push(`offset=${offset}`);
43
+ }
44
+ if (limit !== void 0) {
45
+ params.push(`limit=${limit}`);
46
+ }
47
+ if (after !== void 0) {
48
+ params.push(`after=${encodeURIComponent(after)}`);
49
+ }
40
50
  const query = params.length ? `?${params.join("&")}` : "";
41
51
  const entities = await this.requestRequired("GET", `/entities${query}`, options);
42
52
  const refCompare = (a, b) => {
@@ -54,38 +64,38 @@ class CatalogClient {
54
64
  }
55
65
  return 0;
56
66
  };
57
- return {items: entities.sort(refCompare)};
67
+ return { items: entities.sort(refCompare) };
58
68
  }
59
69
  async getEntityByName(compoundName, options) {
60
- const {kind, namespace = "default", name} = compoundName;
70
+ const { kind, namespace = "default", name } = compoundName;
61
71
  return this.requestOptional("GET", `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(namespace)}/${encodeURIComponent(name)}`, options);
62
72
  }
63
73
  async refreshEntity(entityRef, options) {
64
- const response = await fetch(`${await this.discoveryApi.getBaseUrl("catalog")}/refresh`, {
74
+ const response = await this.fetchApi.fetch(`${await this.discoveryApi.getBaseUrl("catalog")}/refresh`, {
65
75
  headers: {
66
76
  "Content-Type": "application/json",
67
- ...(options == null ? void 0 : options.token) && {Authorization: `Bearer ${options == null ? void 0 : options.token}`}
77
+ ...(options == null ? void 0 : options.token) && { Authorization: `Bearer ${options == null ? void 0 : options.token}` }
68
78
  },
69
79
  method: "POST",
70
- body: JSON.stringify({entityRef})
80
+ body: JSON.stringify({ entityRef })
71
81
  });
72
82
  if (response.status !== 200) {
73
83
  throw new Error(await response.text());
74
84
  }
75
85
  }
76
- async addLocation({type = "url", target, dryRun, presence}, options) {
77
- const response = await fetch(`${await this.discoveryApi.getBaseUrl("catalog")}/locations${dryRun ? "?dryRun=true" : ""}`, {
86
+ async addLocation({ type = "url", target, dryRun, presence }, options) {
87
+ const response = await this.fetchApi.fetch(`${await this.discoveryApi.getBaseUrl("catalog")}/locations${dryRun ? "?dryRun=true" : ""}`, {
78
88
  headers: {
79
89
  "Content-Type": "application/json",
80
- ...(options == null ? void 0 : options.token) && {Authorization: `Bearer ${options == null ? void 0 : options.token}`}
90
+ ...(options == null ? void 0 : options.token) && { Authorization: `Bearer ${options == null ? void 0 : options.token}` }
81
91
  },
82
92
  method: "POST",
83
- body: JSON.stringify({type, target, presence})
93
+ body: JSON.stringify({ type, target, presence })
84
94
  });
85
95
  if (response.status !== 201) {
86
96
  throw new Error(await response.text());
87
97
  }
88
- const {location, entities, exists} = await response.json();
98
+ const { location, entities, exists } = await response.json();
89
99
  if (!location) {
90
100
  throw new Error(`Location wasn't added: ${target}`);
91
101
  }
@@ -121,16 +131,16 @@ class CatalogClient {
121
131
  }
122
132
  async requestIgnored(method, path, options) {
123
133
  const url = `${await this.discoveryApi.getBaseUrl("catalog")}${path}`;
124
- const headers = (options == null ? void 0 : options.token) ? {Authorization: `Bearer ${options.token}`} : {};
125
- const response = await fetch(url, {method, headers});
134
+ const headers = (options == null ? void 0 : options.token) ? { Authorization: `Bearer ${options.token}` } : {};
135
+ const response = await this.fetchApi.fetch(url, { method, headers });
126
136
  if (!response.ok) {
127
137
  throw await ResponseError.fromResponse(response);
128
138
  }
129
139
  }
130
140
  async requestRequired(method, path, options) {
131
141
  const url = `${await this.discoveryApi.getBaseUrl("catalog")}${path}`;
132
- const headers = (options == null ? void 0 : options.token) ? {Authorization: `Bearer ${options.token}`} : {};
133
- const response = await fetch(url, {method, headers});
142
+ const headers = (options == null ? void 0 : options.token) ? { Authorization: `Bearer ${options.token}` } : {};
143
+ const response = await this.fetchApi.fetch(url, { method, headers });
134
144
  if (!response.ok) {
135
145
  throw await ResponseError.fromResponse(response);
136
146
  }
@@ -138,8 +148,8 @@ class CatalogClient {
138
148
  }
139
149
  async requestOptional(method, path, options) {
140
150
  const url = `${await this.discoveryApi.getBaseUrl("catalog")}${path}`;
141
- const headers = (options == null ? void 0 : options.token) ? {Authorization: `Bearer ${options.token}`} : {};
142
- const response = await fetch(url, {method, headers});
151
+ const headers = (options == null ? void 0 : options.token) ? { Authorization: `Bearer ${options.token}` } : {};
152
+ const response = await this.fetchApi.fetch(url, { method, headers });
143
153
  if (!response.ok) {
144
154
  if (response.status === 404) {
145
155
  return void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/types/api.ts","../src/CatalogClient.ts","../src/types/status.ts"],"sourcesContent":["/*\n * Copyright 2021 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 */\n\nimport { Entity, EntityName, Location } from '@backstage/catalog-model';\n\n/**\n * A Symbol to define if a catalog filter exists or not.\n *\n * @public\n */\nexport const CATALOG_FILTER_EXISTS = Symbol('CATALOG_FILTER_EXISTS');\n\n/**\n * A request type for retrieving catalog Entities.\n *\n * @public\n */\nexport type CatalogEntitiesRequest = {\n filter?:\n | Record<string, string | symbol | (string | symbol)[]>[]\n | Record<string, string | symbol | (string | symbol)[]>\n | undefined;\n fields?: string[] | undefined;\n};\n\n/**\n * A request type for Catalog Entity Ancestor information.\n *\n * @public\n */\nexport type CatalogEntityAncestorsRequest = {\n entityRef: string;\n};\n\n/**\n * A response type for Catalog Entity Ancestor information.\n *\n * @public\n */\nexport type CatalogEntityAncestorsResponse = {\n root: EntityName;\n items: { entity: Entity; parents: EntityName[] }[];\n};\n\n/**\n * A response type for the result of a catalog operation in list form.\n *\n * @public\n */\nexport type CatalogListResponse<T> = {\n items: T[];\n};\n\n/**\n * Options you can pass into a catalog request for additional information.\n *\n * @public\n */\nexport type CatalogRequestOptions = {\n token?: string;\n};\n\n/**\n * Public functions for interacting with the Catalog API.\n *\n * @public\n */\nexport interface CatalogApi {\n /**\n * Gets the Entities from the catalog based on your request and options.\n *\n * @param request - An object with your filters and fields.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogListResponse with items typed Catalog Model Entity.\n *\n */\n getEntities(\n request?: CatalogEntitiesRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogListResponse<Entity>>;\n /**\n * Gets the Entity ancestor information from the catalog based on your request and options.\n *\n * @param request - An object with your filters and fields.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogEntityAncestorsResponse.\n */\n getEntityAncestors(\n request: CatalogEntityAncestorsRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogEntityAncestorsResponse>;\n /**\n * Gets a single Entity from the catalog by Entity name.\n *\n * @param name - A complete Entity name, with the full kind-namespace-name triplet.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Entity}.\n */\n getEntityByName(\n name: EntityName,\n options?: CatalogRequestOptions,\n ): Promise<Entity | undefined>;\n /**\n * Removes a single Entity from the catalog by Entity UID.\n *\n * @param uid - A string of the Entity UID.\n * @param options - An object with your preferred options.\n *\n */\n removeEntityByUid(\n uid: string,\n options?: CatalogRequestOptions,\n ): Promise<void>;\n /**\n * Refreshes an Entity in the catalog.\n *\n * @param entityRef - A string in the form of 'Kind/default:foo'.\n * @param options - An object with your preferred options.\n *\n */\n refreshEntity(\n entityRef: string,\n options?: CatalogRequestOptions,\n ): Promise<void>;\n\n // Locations\n /**\n * Gets a Location object by ID from the catalog.\n *\n * @param id - A string in of the Location Id.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n */\n getLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined>;\n /**\n * Gets origin location by Entity.\n *\n * @param entity - An {@link catalog-model#Entity}.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n */\n getOriginLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined>;\n /**\n * Gets Location by Entity.\n *\n * @param entity - An {@link catalog-model#Entity}.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n */\n getLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined>;\n /**\n * Adds a Location.\n *\n * @param location - A request type for adding a Location to the catalog.\n * @param options - An object with your preferred options.\n *\n * @returns A AddLocationResponse.\n */\n addLocation(\n location: AddLocationRequest,\n options?: CatalogRequestOptions,\n ): Promise<AddLocationResponse>;\n /**\n * Removes a Location by Id.\n *\n * @param id - A string in of the Location Id.\n * @param options - An object with your preferred options.\n *\n */\n removeLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<void>;\n}\n\n/**\n * A request type for adding a Location to the catalog.\n *\n * @public\n */\nexport type AddLocationRequest = {\n type?: string;\n target: string;\n dryRun?: boolean;\n presence?: 'optional' | 'required';\n};\n\n/**\n * A response type for adding a Location to the catalog.\n *\n * @public\n */\nexport type AddLocationResponse = {\n location: Location;\n entities: Entity[];\n // Exists is only set in DryRun mode.\n exists?: boolean;\n};\n","/*\n * Copyright 2020 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 */\n\nimport {\n Entity,\n EntityName,\n Location,\n LOCATION_ANNOTATION,\n ORIGIN_LOCATION_ANNOTATION,\n parseEntityRef,\n stringifyEntityRef,\n stringifyLocationReference,\n} from '@backstage/catalog-model';\nimport { ResponseError } from '@backstage/errors';\nimport fetch from 'cross-fetch';\nimport {\n CATALOG_FILTER_EXISTS,\n AddLocationRequest,\n AddLocationResponse,\n CatalogApi,\n CatalogEntitiesRequest,\n CatalogListResponse,\n CatalogRequestOptions,\n CatalogEntityAncestorsRequest,\n CatalogEntityAncestorsResponse,\n} from './types/api';\nimport { DiscoveryApi } from './types/discovery';\n\n/**\n * A frontend and backend compatible client for communicating with the Backstage Catalog.\n *\n * @public\n * */\nexport class CatalogClient implements CatalogApi {\n private readonly discoveryApi: DiscoveryApi;\n\n constructor(options: { discoveryApi: DiscoveryApi }) {\n this.discoveryApi = options.discoveryApi;\n }\n\n /**\n * Gets the Ancestors of an Entity.\n *\n * @param request - A request type for retrieving Entity ancestors.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogEntityAncestorsResponse.\n *\n * @public\n */\n async getEntityAncestors(\n request: CatalogEntityAncestorsRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogEntityAncestorsResponse> {\n const { kind, namespace, name } = parseEntityRef(request.entityRef);\n return await this.requestRequired(\n 'GET',\n `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(\n namespace,\n )}/${encodeURIComponent(name)}/ancestry`,\n options,\n );\n }\n\n /**\n * Gets a Location by Id.\n *\n * @param id - A string containing the Id.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n return await this.requestOptional(\n 'GET',\n `/locations/${encodeURIComponent(id)}`,\n options,\n );\n }\n\n /**\n * Gets a set of Entities.\n *\n * @param request - A request type for retrieving an Entity.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogListResponse.\n *\n * @public\n */\n async getEntities(\n request?: CatalogEntitiesRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogListResponse<Entity>> {\n const { filter = [], fields = [] } = request ?? {};\n const filterItems = [filter].flat();\n const params: string[] = [];\n\n // filter param can occur multiple times, for example\n // /api/catalog/entities?filter=metadata.name=wayback-search,kind=component&filter=metadata.name=www-artist,kind=component'\n // the \"outer array\" defined by `filter` occurrences corresponds to \"anyOf\" filters\n // the \"inner array\" defined within a `filter` param corresponds to \"allOf\" filters\n for (const filterItem of filterItems) {\n const filterParts: string[] = [];\n for (const [key, value] of Object.entries(filterItem)) {\n for (const v of [value].flat()) {\n if (v === CATALOG_FILTER_EXISTS) {\n filterParts.push(encodeURIComponent(key));\n } else if (typeof v === 'string') {\n filterParts.push(\n `${encodeURIComponent(key)}=${encodeURIComponent(v)}`,\n );\n }\n }\n }\n\n if (filterParts.length) {\n params.push(`filter=${filterParts.join(',')}`);\n }\n }\n\n if (fields.length) {\n params.push(`fields=${fields.map(encodeURIComponent).join(',')}`);\n }\n\n const query = params.length ? `?${params.join('&')}` : '';\n const entities: Entity[] = await this.requestRequired(\n 'GET',\n `/entities${query}`,\n options,\n );\n\n const refCompare = (a: Entity, b: Entity) => {\n // in case field filtering is used, these fields might not be part of the response\n if (\n a.metadata?.name === undefined ||\n a.kind === undefined ||\n b.metadata?.name === undefined ||\n b.kind === undefined\n ) {\n return 0;\n }\n\n const aRef = stringifyEntityRef(a);\n const bRef = stringifyEntityRef(b);\n if (aRef < bRef) {\n return -1;\n }\n if (aRef > bRef) {\n return 1;\n }\n return 0;\n };\n\n return { items: entities.sort(refCompare) };\n }\n\n /**\n * Gets a given Entity based on a provided name.\n *\n * @param compoundName - A string containing the name.\n * @param options - An object with your preferred options.\n *\n * @returns An {@link catalog-model#Entity}.\n *\n * @public\n */\n async getEntityByName(\n compoundName: EntityName,\n options?: CatalogRequestOptions,\n ): Promise<Entity | undefined> {\n const { kind, namespace = 'default', name } = compoundName;\n return this.requestOptional(\n 'GET',\n `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(\n namespace,\n )}/${encodeURIComponent(name)}`,\n options,\n );\n }\n\n /**\n * Refreshes an Entity.\n *\n * @param entityRef - A string containing the entityREf\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async refreshEntity(entityRef: string, options?: CatalogRequestOptions) {\n const response = await fetch(\n `${await this.discoveryApi.getBaseUrl('catalog')}/refresh`,\n {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'POST',\n body: JSON.stringify({ entityRef }),\n },\n );\n\n if (response.status !== 200) {\n throw new Error(await response.text());\n }\n }\n\n /**\n * Adds a location.\n *\n * @param options - An object with your preferred options.\n * @param AddLocationRequest - A request object for adding locations.\n *\n * @returns An AddLocationResponse\n *\n * @public\n */\n async addLocation(\n { type = 'url', target, dryRun, presence }: AddLocationRequest,\n options?: CatalogRequestOptions,\n ): Promise<AddLocationResponse> {\n const response = await fetch(\n `${await this.discoveryApi.getBaseUrl('catalog')}/locations${\n dryRun ? '?dryRun=true' : ''\n }`,\n {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'POST',\n body: JSON.stringify({ type, target, presence }),\n },\n );\n\n if (response.status !== 201) {\n throw new Error(await response.text());\n }\n\n const { location, entities, exists } = await response.json();\n\n if (!location) {\n throw new Error(`Location wasn't added: ${target}`);\n }\n\n return {\n location,\n entities,\n exists,\n };\n }\n\n /**\n * Gets an origin Location By Entity.\n *\n * @param entity - An Entity\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getOriginLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n const locationCompound =\n entity.metadata.annotations?.[ORIGIN_LOCATION_ANNOTATION];\n if (!locationCompound) {\n return undefined;\n }\n const all: { data: Location }[] = await this.requestRequired(\n 'GET',\n '/locations',\n options,\n );\n return all\n .map(r => r.data)\n .find(l => locationCompound === stringifyLocationReference(l));\n }\n\n /**\n * Gets a Location by Entity.\n *\n * @param entity - An Entity\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n const locationCompound = entity.metadata.annotations?.[LOCATION_ANNOTATION];\n if (!locationCompound) {\n return undefined;\n }\n const all: { data: Location }[] = await this.requestRequired(\n 'GET',\n '/locations',\n options,\n );\n return all\n .map(r => r.data)\n .find(l => locationCompound === stringifyLocationReference(l));\n }\n\n /**\n * Removes a location as identified by Id.\n *\n * @param id - A string containing the Id\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async removeLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n await this.requestIgnored(\n 'DELETE',\n `/locations/${encodeURIComponent(id)}`,\n options,\n );\n }\n\n /**\n * Removes an Entity as identified by Uid.\n *\n * @param uid - A string containing the Uid\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async removeEntityByUid(\n uid: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n await this.requestIgnored(\n 'DELETE',\n `/entities/by-uid/${encodeURIComponent(uid)}`,\n options,\n );\n }\n\n //\n // Private methods\n //\n\n private async requestIgnored(\n method: string,\n path: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers: Record<string, string> = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await fetch(url, { method, headers });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n }\n\n private async requestRequired(\n method: string,\n path: string,\n options?: CatalogRequestOptions,\n ): Promise<any> {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers: Record<string, string> = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await fetch(url, { method, headers });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n\n private async requestOptional(\n method: string,\n path: string,\n options?: CatalogRequestOptions,\n ): Promise<any | undefined> {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers: Record<string, string> = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await fetch(url, { method, headers });\n\n if (!response.ok) {\n if (response.status === 404) {\n return undefined;\n }\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n}\n","/*\n * Copyright 2021 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 */\n\n/**\n * The entity `status.items[].type` for the status of the processing engine in\n * regards to an entity.\n *\n * @public\n */\nexport const ENTITY_STATUS_CATALOG_PROCESSING_TYPE =\n 'backstage.io/catalog-processing';\n"],"names":[],"mappings":";;;;MAuBa,wBAAwB,OAAO;;oBCuBK;AAAA,EAG/C,YAAY,SAAyC;AACnD,SAAK,eAAe,QAAQ;AAAA;AAAA,QAaxB,mBACJ,SACA,SACyC;AACzC,UAAM,CAAE,MAAM,WAAW,QAAS,eAAe,QAAQ;AACzD,WAAO,MAAM,KAAK,gBAChB,OACA,qBAAqB,mBAAmB,SAAS,mBAC/C,cACG,mBAAmB,kBACxB;AAAA;AAAA,QAcE,gBACJ,IACA,SAC+B;AAC/B,WAAO,MAAM,KAAK,gBAChB,OACA,cAAc,mBAAmB,OACjC;AAAA;AAAA,QAcE,YACJ,SACA,SACsC;AACtC,UAAM,CAAE,SAAS,IAAI,SAAS,MAAO,4BAAW;AAChD,UAAM,cAAc,CAAC,QAAQ;AAC7B,UAAM,SAAmB;AAMzB,eAAW,cAAc,aAAa;AACpC,YAAM,cAAwB;AAC9B,iBAAW,CAAC,KAAK,UAAU,OAAO,QAAQ,aAAa;AACrD,mBAAW,KAAK,CAAC,OAAO,QAAQ;AAC9B,cAAI,MAAM,uBAAuB;AAC/B,wBAAY,KAAK,mBAAmB;AAAA,qBAC3B,OAAO,MAAM,UAAU;AAChC,wBAAY,KACV,GAAG,mBAAmB,QAAQ,mBAAmB;AAAA;AAAA;AAAA;AAMzD,UAAI,YAAY,QAAQ;AACtB,eAAO,KAAK,UAAU,YAAY,KAAK;AAAA;AAAA;AAI3C,QAAI,OAAO,QAAQ;AACjB,aAAO,KAAK,UAAU,OAAO,IAAI,oBAAoB,KAAK;AAAA;AAG5D,UAAM,QAAQ,OAAO,SAAS,IAAI,OAAO,KAAK,SAAS;AACvD,UAAM,WAAqB,MAAM,KAAK,gBACpC,OACA,YAAY,SACZ;AAGF,UAAM,aAAa,CAAC,GAAW,MAAc;AAtJjD;AAwJM,UACE,SAAE,aAAF,mBAAY,UAAS,UACrB,EAAE,SAAS,UACX,SAAE,aAAF,mBAAY,UAAS,UACrB,EAAE,SAAS,QACX;AACA,eAAO;AAAA;AAGT,YAAM,OAAO,mBAAmB;AAChC,YAAM,OAAO,mBAAmB;AAChC,UAAI,OAAO,MAAM;AACf,eAAO;AAAA;AAET,UAAI,OAAO,MAAM;AACf,eAAO;AAAA;AAET,aAAO;AAAA;AAGT,WAAO,CAAE,OAAO,SAAS,KAAK;AAAA;AAAA,QAa1B,gBACJ,cACA,SAC6B;AAC7B,UAAM,CAAE,MAAM,YAAY,WAAW,QAAS;AAC9C,WAAO,KAAK,gBACV,OACA,qBAAqB,mBAAmB,SAAS,mBAC/C,cACG,mBAAmB,SACxB;AAAA;AAAA,QAYE,cAAc,WAAmB,SAAiC;AACtE,UAAM,WAAW,MAAM,MACrB,GAAG,MAAM,KAAK,aAAa,WAAW,sBACtC;AAAA,MACE,SAAS;AAAA,QACP,gBAAgB;AAAA,WACZ,oCAAS,UAAS,CAAE,eAAe,UAAU,mCAAS;AAAA;AAAA,MAE5D,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,CAAE;AAAA;AAI3B,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,MAAM,SAAS;AAAA;AAAA;AAAA,QAc7B,YACJ,CAAE,OAAO,OAAO,QAAQ,QAAQ,WAChC,SAC8B;AAC9B,UAAM,WAAW,MAAM,MACrB,GAAG,MAAM,KAAK,aAAa,WAAW,uBACpC,SAAS,iBAAiB,MAE5B;AAAA,MACE,SAAS;AAAA,QACP,gBAAgB;AAAA,WACZ,oCAAS,UAAS,CAAE,eAAe,UAAU,mCAAS;AAAA;AAAA,MAE5D,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,CAAE,MAAM,QAAQ;AAAA;AAIzC,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,MAAM,SAAS;AAAA;AAGjC,UAAM,CAAE,UAAU,UAAU,UAAW,MAAM,SAAS;AAEtD,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,0BAA0B;AAAA;AAG5C,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA;AAAA;AAAA,QAcE,0BACJ,QACA,SAC+B;AA3RnC;AA4RI,UAAM,mBACJ,aAAO,SAAS,gBAAhB,mBAA8B;AAChC,QAAI,CAAC,kBAAkB;AACrB,aAAO;AAAA;AAET,UAAM,MAA4B,MAAM,KAAK,gBAC3C,OACA,cACA;AAEF,WAAO,IACJ,IAAI,OAAK,EAAE,MACX,KAAK,OAAK,qBAAqB,2BAA2B;AAAA;AAAA,QAazD,oBACJ,QACA,SAC+B;AAxTnC;AAyTI,UAAM,mBAAmB,aAAO,SAAS,gBAAhB,mBAA8B;AACvD,QAAI,CAAC,kBAAkB;AACrB,aAAO;AAAA;AAET,UAAM,MAA4B,MAAM,KAAK,gBAC3C,OACA,cACA;AAEF,WAAO,IACJ,IAAI,OAAK,EAAE,MACX,KAAK,OAAK,qBAAqB,2BAA2B;AAAA;AAAA,QAWzD,mBACJ,IACA,SACe;AACf,UAAM,KAAK,eACT,UACA,cAAc,mBAAmB,OACjC;AAAA;AAAA,QAYE,kBACJ,KACA,SACe;AACf,UAAM,KAAK,eACT,UACA,oBAAoB,mBAAmB,QACvC;AAAA;AAAA,QAQU,eACZ,QACA,MACA,SACe;AACf,UAAM,MAAM,GAAG,MAAM,KAAK,aAAa,WAAW,aAAa;AAC/D,UAAM,UAAkC,oCAAS,SAC7C,CAAE,eAAe,UAAU,QAAQ,WACnC;AACJ,UAAM,WAAW,MAAM,MAAM,KAAK,CAAE,QAAQ;AAE5C,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,MAAM,cAAc,aAAa;AAAA;AAAA;AAAA,QAI7B,gBACZ,QACA,MACA,SACc;AACd,UAAM,MAAM,GAAG,MAAM,KAAK,aAAa,WAAW,aAAa;AAC/D,UAAM,UAAkC,oCAAS,SAC7C,CAAE,eAAe,UAAU,QAAQ,WACnC;AACJ,UAAM,WAAW,MAAM,MAAM,KAAK,CAAE,QAAQ;AAE5C,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,MAAM,cAAc,aAAa;AAAA;AAGzC,WAAO,MAAM,SAAS;AAAA;AAAA,QAGV,gBACZ,QACA,MACA,SAC0B;AAC1B,UAAM,MAAM,GAAG,MAAM,KAAK,aAAa,WAAW,aAAa;AAC/D,UAAM,UAAkC,oCAAS,SAC7C,CAAE,eAAe,UAAU,QAAQ,WACnC;AACJ,UAAM,WAAW,MAAM,MAAM,KAAK,CAAE,QAAQ;AAE5C,QAAI,CAAC,SAAS,IAAI;AAChB,UAAI,SAAS,WAAW,KAAK;AAC3B,eAAO;AAAA;AAET,YAAM,MAAM,cAAc,aAAa;AAAA;AAGzC,WAAO,MAAM,SAAS;AAAA;AAAA;;MC/Yb,wCACX;;;;"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/types/api.ts","../src/CatalogClient.ts","../src/types/status.ts"],"sourcesContent":["/*\n * Copyright 2021 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 */\n\nimport { Entity, EntityName, Location } from '@backstage/catalog-model';\n\n/**\n * A Symbol to define if a catalog filter exists or not.\n *\n * @public\n */\nexport const CATALOG_FILTER_EXISTS = Symbol('CATALOG_FILTER_EXISTS');\n\n/**\n * A request type for retrieving catalog Entities.\n *\n * @public\n */\nexport type CatalogEntitiesRequest = {\n /**\n * If given, return only entities that match the given patterns.\n *\n * @remarks\n *\n * If multiple filter sets are given as an array, then there is effectively an\n * OR between each filter set.\n *\n * Within one filter set, there is effectively an AND between the various\n * keys.\n *\n * Within one key, if there are more than one value, then there is effectively\n * an OR between them.\n *\n * Example: For an input of\n *\n * ```\n * [\n * { kind: ['API', 'Component'] },\n * { 'metadata.name': 'a', 'metadata.namespace': 'b' }\n * ]\n * ```\n *\n * This effectively means\n *\n * ```\n * (kind = EITHER 'API' OR 'Component')\n * OR\n * (metadata.name = 'a' AND metadata.namespace = 'b' )\n * ```\n *\n * Each key is a dot separated path in each object.\n *\n * As a value you can also pass in the symbol `CATALOG_FILTER_EXISTS`\n * (exported from this package), which means that you assert on the existence\n * of that key, no matter what its value is.\n */\n filter?:\n | Record<string, string | symbol | (string | symbol)[]>[]\n | Record<string, string | symbol | (string | symbol)[]>\n | undefined;\n /**\n * If given, return only the parts of each entity that match those dot\n * separated paths in each object.\n *\n * @remarks\n *\n * Example: For an input of `['kind', 'metadata.annotations']`, then response\n * objects will be shaped like\n *\n * ```\n * {\n * \"kind\": \"Component\",\n * \"metadata\": {\n * \"annotations\": {\n * \"foo\": \"bar\"\n * }\n * }\n * }\n * ```\n */\n fields?: string[] | undefined;\n /**\n * If given, skips over the first N items in the result set.\n */\n offset?: number;\n /**\n * If given, returns at most N items from the result set.\n */\n limit?: number;\n /**\n * If given, skips over all items before that cursor as returned by a previous\n * request.\n */\n after?: string;\n};\n\n/**\n * A request type for Catalog Entity Ancestor information.\n *\n * @public\n */\nexport type CatalogEntityAncestorsRequest = {\n entityRef: string;\n};\n\n/**\n * A response type for Catalog Entity Ancestor information.\n *\n * @public\n */\nexport type CatalogEntityAncestorsResponse = {\n root: EntityName;\n items: { entity: Entity; parents: EntityName[] }[];\n};\n\n/**\n * A response type for the result of a catalog operation in list form.\n *\n * @public\n */\nexport type CatalogListResponse<T> = {\n items: T[];\n};\n\n/**\n * Options you can pass into a catalog request for additional information.\n *\n * @public\n */\nexport type CatalogRequestOptions = {\n token?: string;\n};\n\n/**\n * Public functions for interacting with the Catalog API.\n *\n * @public\n */\nexport interface CatalogApi {\n /**\n * Gets the Entities from the catalog based on your request and options.\n *\n * @param request - An object with your filters and fields.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogListResponse with items typed Catalog Model Entity.\n *\n */\n getEntities(\n request?: CatalogEntitiesRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogListResponse<Entity>>;\n /**\n * Gets the Entity ancestor information from the catalog based on your request and options.\n *\n * @param request - An object with your filters and fields.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogEntityAncestorsResponse.\n */\n getEntityAncestors(\n request: CatalogEntityAncestorsRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogEntityAncestorsResponse>;\n /**\n * Gets a single Entity from the catalog by Entity name.\n *\n * @param name - A complete Entity name, with the full kind-namespace-name triplet.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Entity}.\n */\n getEntityByName(\n name: EntityName,\n options?: CatalogRequestOptions,\n ): Promise<Entity | undefined>;\n /**\n * Removes a single Entity from the catalog by Entity UID.\n *\n * @param uid - A string of the Entity UID.\n * @param options - An object with your preferred options.\n *\n */\n removeEntityByUid(\n uid: string,\n options?: CatalogRequestOptions,\n ): Promise<void>;\n /**\n * Refreshes an Entity in the catalog.\n *\n * @param entityRef - A string in the form of 'Kind/default:foo'.\n * @param options - An object with your preferred options.\n *\n */\n refreshEntity(\n entityRef: string,\n options?: CatalogRequestOptions,\n ): Promise<void>;\n\n // Locations\n /**\n * Gets a Location object by ID from the catalog.\n *\n * @param id - A string in of the Location Id.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n */\n getLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined>;\n /**\n * Gets origin location by Entity.\n *\n * @param entity - An {@link catalog-model#Entity}.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n */\n getOriginLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined>;\n /**\n * Gets Location by Entity.\n *\n * @param entity - An {@link catalog-model#Entity}.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n */\n getLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined>;\n /**\n * Adds a Location.\n *\n * @param location - A request type for adding a Location to the catalog.\n * @param options - An object with your preferred options.\n *\n * @returns A AddLocationResponse.\n */\n addLocation(\n location: AddLocationRequest,\n options?: CatalogRequestOptions,\n ): Promise<AddLocationResponse>;\n /**\n * Removes a Location by Id.\n *\n * @param id - A string in of the Location Id.\n * @param options - An object with your preferred options.\n *\n */\n removeLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<void>;\n}\n\n/**\n * A request type for adding a Location to the catalog.\n *\n * @public\n */\nexport type AddLocationRequest = {\n type?: string;\n target: string;\n dryRun?: boolean;\n presence?: 'optional' | 'required';\n};\n\n/**\n * A response type for adding a Location to the catalog.\n *\n * @public\n */\nexport type AddLocationResponse = {\n location: Location;\n entities: Entity[];\n // Exists is only set in DryRun mode.\n exists?: boolean;\n};\n","/*\n * Copyright 2020 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 */\n\nimport {\n Entity,\n EntityName,\n Location,\n LOCATION_ANNOTATION,\n ORIGIN_LOCATION_ANNOTATION,\n parseEntityRef,\n stringifyEntityRef,\n stringifyLocationReference,\n} from '@backstage/catalog-model';\nimport { ResponseError } from '@backstage/errors';\nimport crossFetch from 'cross-fetch';\nimport {\n CATALOG_FILTER_EXISTS,\n AddLocationRequest,\n AddLocationResponse,\n CatalogApi,\n CatalogEntitiesRequest,\n CatalogListResponse,\n CatalogRequestOptions,\n CatalogEntityAncestorsRequest,\n CatalogEntityAncestorsResponse,\n} from './types/api';\nimport { DiscoveryApi } from './types/discovery';\nimport { FetchApi } from './types/fetch';\n\n/**\n * A frontend and backend compatible client for communicating with the Backstage Catalog.\n *\n * @public\n * */\nexport class CatalogClient implements CatalogApi {\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 /**\n * Gets the Ancestors of an Entity.\n *\n * @param request - A request type for retrieving Entity ancestors.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogEntityAncestorsResponse.\n *\n * @public\n */\n async getEntityAncestors(\n request: CatalogEntityAncestorsRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogEntityAncestorsResponse> {\n const { kind, namespace, name } = parseEntityRef(request.entityRef);\n return await this.requestRequired(\n 'GET',\n `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(\n namespace,\n )}/${encodeURIComponent(name)}/ancestry`,\n options,\n );\n }\n\n /**\n * Gets a Location by Id.\n *\n * @param id - A string containing the Id.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n return await this.requestOptional(\n 'GET',\n `/locations/${encodeURIComponent(id)}`,\n options,\n );\n }\n\n /**\n * Gets a set of Entities.\n *\n * @param request - A request type for retrieving an Entity.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogListResponse.\n *\n * @public\n */\n async getEntities(\n request?: CatalogEntitiesRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogListResponse<Entity>> {\n const { filter = [], fields = [], offset, limit, after } = request ?? {};\n const filterItems = [filter].flat();\n const params: string[] = [];\n\n // filter param can occur multiple times, for example\n // /api/catalog/entities?filter=metadata.name=wayback-search,kind=component&filter=metadata.name=www-artist,kind=component'\n // the \"outer array\" defined by `filter` occurrences corresponds to \"anyOf\" filters\n // the \"inner array\" defined within a `filter` param corresponds to \"allOf\" filters\n for (const filterItem of filterItems) {\n const filterParts: string[] = [];\n for (const [key, value] of Object.entries(filterItem)) {\n for (const v of [value].flat()) {\n if (v === CATALOG_FILTER_EXISTS) {\n filterParts.push(encodeURIComponent(key));\n } else if (typeof v === 'string') {\n filterParts.push(\n `${encodeURIComponent(key)}=${encodeURIComponent(v)}`,\n );\n }\n }\n }\n\n if (filterParts.length) {\n params.push(`filter=${filterParts.join(',')}`);\n }\n }\n\n if (fields.length) {\n params.push(`fields=${fields.map(encodeURIComponent).join(',')}`);\n }\n\n if (offset !== undefined) {\n params.push(`offset=${offset}`);\n }\n if (limit !== undefined) {\n params.push(`limit=${limit}`);\n }\n if (after !== undefined) {\n params.push(`after=${encodeURIComponent(after)}`);\n }\n\n const query = params.length ? `?${params.join('&')}` : '';\n const entities: Entity[] = await this.requestRequired(\n 'GET',\n `/entities${query}`,\n options,\n );\n\n const refCompare = (a: Entity, b: Entity) => {\n // in case field filtering is used, these fields might not be part of the response\n if (\n a.metadata?.name === undefined ||\n a.kind === undefined ||\n b.metadata?.name === undefined ||\n b.kind === undefined\n ) {\n return 0;\n }\n\n const aRef = stringifyEntityRef(a);\n const bRef = stringifyEntityRef(b);\n if (aRef < bRef) {\n return -1;\n }\n if (aRef > bRef) {\n return 1;\n }\n return 0;\n };\n\n return { items: entities.sort(refCompare) };\n }\n\n /**\n * Gets a given Entity based on a provided name.\n *\n * @param compoundName - A string containing the name.\n * @param options - An object with your preferred options.\n *\n * @returns An {@link catalog-model#Entity}.\n *\n * @public\n */\n async getEntityByName(\n compoundName: EntityName,\n options?: CatalogRequestOptions,\n ): Promise<Entity | undefined> {\n const { kind, namespace = 'default', name } = compoundName;\n return this.requestOptional(\n 'GET',\n `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(\n namespace,\n )}/${encodeURIComponent(name)}`,\n options,\n );\n }\n\n /**\n * Refreshes an Entity.\n *\n * @param entityRef - A string containing the entityREf\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async refreshEntity(entityRef: string, options?: CatalogRequestOptions) {\n const response = await this.fetchApi.fetch(\n `${await this.discoveryApi.getBaseUrl('catalog')}/refresh`,\n {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'POST',\n body: JSON.stringify({ entityRef }),\n },\n );\n\n if (response.status !== 200) {\n throw new Error(await response.text());\n }\n }\n\n /**\n * Adds a location.\n *\n * @param options - An object with your preferred options.\n * @param AddLocationRequest - A request object for adding locations.\n *\n * @returns An AddLocationResponse\n *\n * @public\n */\n async addLocation(\n { type = 'url', target, dryRun, presence }: AddLocationRequest,\n options?: CatalogRequestOptions,\n ): Promise<AddLocationResponse> {\n const response = await this.fetchApi.fetch(\n `${await this.discoveryApi.getBaseUrl('catalog')}/locations${\n dryRun ? '?dryRun=true' : ''\n }`,\n {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'POST',\n body: JSON.stringify({ type, target, presence }),\n },\n );\n\n if (response.status !== 201) {\n throw new Error(await response.text());\n }\n\n const { location, entities, exists } = await response.json();\n\n if (!location) {\n throw new Error(`Location wasn't added: ${target}`);\n }\n\n return {\n location,\n entities,\n exists,\n };\n }\n\n /**\n * Gets an origin Location By Entity.\n *\n * @param entity - An Entity\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getOriginLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n const locationCompound =\n entity.metadata.annotations?.[ORIGIN_LOCATION_ANNOTATION];\n if (!locationCompound) {\n return undefined;\n }\n const all: { data: Location }[] = await this.requestRequired(\n 'GET',\n '/locations',\n options,\n );\n return all\n .map(r => r.data)\n .find(l => locationCompound === stringifyLocationReference(l));\n }\n\n /**\n * Gets a Location by Entity.\n *\n * @param entity - An Entity\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n const locationCompound = entity.metadata.annotations?.[LOCATION_ANNOTATION];\n if (!locationCompound) {\n return undefined;\n }\n const all: { data: Location }[] = await this.requestRequired(\n 'GET',\n '/locations',\n options,\n );\n return all\n .map(r => r.data)\n .find(l => locationCompound === stringifyLocationReference(l));\n }\n\n /**\n * Removes a location as identified by Id.\n *\n * @param id - A string containing the Id\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async removeLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n await this.requestIgnored(\n 'DELETE',\n `/locations/${encodeURIComponent(id)}`,\n options,\n );\n }\n\n /**\n * Removes an Entity as identified by Uid.\n *\n * @param uid - A string containing the Uid\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async removeEntityByUid(\n uid: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n await this.requestIgnored(\n 'DELETE',\n `/entities/by-uid/${encodeURIComponent(uid)}`,\n options,\n );\n }\n\n //\n // Private methods\n //\n\n private async requestIgnored(\n method: string,\n path: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers: Record<string, string> = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await this.fetchApi.fetch(url, { method, headers });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n }\n\n private async requestRequired(\n method: string,\n path: string,\n options?: CatalogRequestOptions,\n ): Promise<any> {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers: Record<string, string> = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await this.fetchApi.fetch(url, { method, headers });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n\n private async requestOptional(\n method: string,\n path: string,\n options?: CatalogRequestOptions,\n ): Promise<any | undefined> {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers: Record<string, string> = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await this.fetchApi.fetch(url, { method, headers });\n\n if (!response.ok) {\n if (response.status === 404) {\n return undefined;\n }\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n}\n","/*\n * Copyright 2021 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 */\n\n/**\n * The entity `status.items[].type` for the status of the processing engine in\n * regards to an entity.\n *\n * @public\n */\nexport const ENTITY_STATUS_CATALOG_PROCESSING_TYPE =\n 'backstage.io/catalog-processing';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@backstage/catalog-client",
3
3
  "description": "An isomorphic client for the catalog backend",
4
- "version": "0.5.2",
4
+ "version": "0.5.5",
5
5
  "main": "dist/index.cjs.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "license": "Apache-2.0",
@@ -30,18 +30,18 @@
30
30
  "clean": "backstage-cli clean"
31
31
  },
32
32
  "dependencies": {
33
- "@backstage/catalog-model": "^0.9.7",
34
- "@backstage/errors": "^0.1.4",
33
+ "@backstage/catalog-model": "^0.9.10",
34
+ "@backstage/errors": "^0.2.0",
35
35
  "cross-fetch": "^3.0.6"
36
36
  },
37
37
  "devDependencies": {
38
- "@backstage/cli": "^0.9.0",
38
+ "@backstage/cli": "^0.12.0",
39
39
  "@types/jest": "^26.0.7",
40
40
  "msw": "^0.35.0"
41
41
  },
42
42
  "files": [
43
43
  "dist"
44
44
  ],
45
- "gitHead": "ddfdcd2b44dc9848cf550cea5346d5f9916a36d9",
45
+ "gitHead": "600d6e3c854bbfb12a0078ca6f726d1c0d1fea0b",
46
46
  "module": "dist/index.esm.js"
47
47
  }