@backstage/plugin-catalog-backend-module-msgraph 0.9.1-next.0 → 0.9.1-next.1

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,14 @@
1
1
  # @backstage/plugin-catalog-backend-module-msgraph
2
2
 
3
+ ## 0.9.1-next.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 97eaecf: Fixed scheduler task remaining stuck in running state after pod termination by propagating AbortSignal into MicrosoftGraphOrgEntityProvider.read()
8
+ - Updated dependencies
9
+ - @backstage/backend-plugin-api@1.8.0-next.1
10
+ - @backstage/plugin-catalog-node@2.1.0-next.2
11
+
3
12
  ## 0.9.1-next.0
4
13
 
5
14
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -313,7 +313,7 @@ declare class MicrosoftGraphClient {
313
313
  * @param query - OData Query {@link ODataQuery}
314
314
  * @param queryMode - Mode to use while querying. Some features are only available at "advanced".
315
315
  */
316
- requestCollection<T>(path: string, query?: ODataQuery, queryMode?: 'basic' | 'advanced'): AsyncIterable<T>;
316
+ requestCollection<T>(path: string, query?: ODataQuery, queryMode?: 'basic' | 'advanced', signal?: AbortSignal): AsyncIterable<T>;
317
317
  /**
318
318
  * Abstract on top of {@link MicrosoftGraphClient.requestRaw}
319
319
  *
@@ -322,14 +322,14 @@ declare class MicrosoftGraphClient {
322
322
  * @param query - OData Query {@link ODataQuery}
323
323
  * @param headers - optional HTTP headers
324
324
  */
325
- requestApi(path: string, query?: ODataQuery, headers?: Record<string, string>): Promise<Response>;
325
+ requestApi(path: string, query?: ODataQuery, headers?: Record<string, string>, signal?: AbortSignal): Promise<Response>;
326
326
  /**
327
327
  * Makes a HTTP call to Graph API with token
328
328
  *
329
329
  * @param url - HTTP Endpoint of Graph API
330
330
  * @param headers - optional HTTP headers
331
331
  */
332
- requestRaw(url: string, headers?: Record<string, string>, retryCount?: number): Promise<Response>;
332
+ requestRaw(url: string, headers?: Record<string, string>, retryCount?: number, signal?: AbortSignal): Promise<Response>;
333
333
  /**
334
334
  * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto}
335
335
  * of `User` from Graph API with size limit
@@ -350,7 +350,7 @@ declare class MicrosoftGraphClient {
350
350
  * @param queryMode - Mode to use while querying. Some features are only available at "advanced".
351
351
  * @param path - Resource endpoint in Microsoft Graph
352
352
  */
353
- getUsers(query?: ODataQuery, queryMode?: 'basic' | 'advanced', path?: string): AsyncIterable<MicrosoftGraph.User>;
353
+ getUsers(query?: ODataQuery, queryMode?: 'basic' | 'advanced', path?: string, signal?: AbortSignal): AsyncIterable<MicrosoftGraph.User>;
354
354
  /**
355
355
  * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto}
356
356
  * of `Group` from Graph API with size limit
@@ -371,7 +371,7 @@ declare class MicrosoftGraphClient {
371
371
  * @param queryMode - Mode to use while querying. Some features are only available at "advanced".
372
372
  * @param path - Resource endpoint in Microsoft Graph
373
373
  */
374
- getGroups(query?: ODataQuery, queryMode?: 'basic' | 'advanced', path?: string): AsyncIterable<MicrosoftGraph.Group>;
374
+ getGroups(query?: ODataQuery, queryMode?: 'basic' | 'advanced', path?: string, signal?: AbortSignal): AsyncIterable<MicrosoftGraph.Group>;
375
375
  /**
376
376
  * Get a collection of
377
377
  * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User}
@@ -380,7 +380,7 @@ declare class MicrosoftGraphClient {
380
380
  * @param groupId - The unique identifier for the `Group` resource
381
381
  *
382
382
  */
383
- getGroupMembers(groupId: string, query?: ODataQuery, queryMode?: 'basic' | 'advanced'): AsyncIterable<GroupMember>;
383
+ getGroupMembers(groupId: string, query?: ODataQuery, queryMode?: 'basic' | 'advanced', signal?: AbortSignal): AsyncIterable<GroupMember>;
384
384
  /**
385
385
  * Get a collection of
386
386
  * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User}
@@ -390,7 +390,7 @@ declare class MicrosoftGraphClient {
390
390
  * @param query - OData Query {@link ODataQuery}
391
391
  * @param queryMode - Mode to use while querying. Some features are only available at "advanced".
392
392
  */
393
- getGroupUserMembers(groupId: string, query?: ODataQuery, queryMode?: 'basic' | 'advanced'): AsyncIterable<MicrosoftGraph.User>;
393
+ getGroupUserMembers(groupId: string, query?: ODataQuery, queryMode?: 'basic' | 'advanced', signal?: AbortSignal): AsyncIterable<MicrosoftGraph.User>;
394
394
  /**
395
395
  * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/organization | Organization}
396
396
  * from Graph API
@@ -398,7 +398,7 @@ declare class MicrosoftGraphClient {
398
398
  * @param tenantId - The unique identifier for the `Organization` resource
399
399
  *
400
400
  */
401
- getOrganization(tenantId: string): Promise<MicrosoftGraph.Organization>;
401
+ getOrganization(tenantId: string, signal?: AbortSignal): Promise<MicrosoftGraph.Organization>;
402
402
  /**
403
403
  * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto}
404
404
  * from Graph API
@@ -492,6 +492,7 @@ declare function readMicrosoftGraphOrg(client: MicrosoftGraphClient, tenantId: s
492
492
  groupTransformer?: GroupTransformer;
493
493
  organizationTransformer?: OrganizationTransformer;
494
494
  logger: LoggerService;
495
+ signal?: AbortSignal;
495
496
  }): Promise<{
496
497
  users: UserEntity[];
497
498
  groups: GroupEntity[];
@@ -634,6 +635,7 @@ declare class MicrosoftGraphOrgEntityProvider implements EntityProvider {
634
635
  */
635
636
  read(options?: {
636
637
  logger?: LoggerService;
638
+ signal?: AbortSignal;
637
639
  }): Promise<void>;
638
640
  private schedule;
639
641
  }
@@ -49,7 +49,7 @@ class MicrosoftGraphClient {
49
49
  * @param query - OData Query {@link ODataQuery}
50
50
  * @param queryMode - Mode to use while querying. Some features are only available at "advanced".
51
51
  */
52
- async *requestCollection(path, query, queryMode) {
52
+ async *requestCollection(path, query, queryMode, signal) {
53
53
  const appliedQueryMode = query?.search ? "advanced" : queryMode ?? "basic";
54
54
  if (appliedQueryMode === "advanced" && (query?.filter || query?.select)) {
55
55
  query.count = true;
@@ -60,7 +60,7 @@ class MicrosoftGraphClient {
60
60
  // If a new user/group is not found, it'll eventually be imported on a subsequent read
61
61
  ConsistencyLevel: "eventual"
62
62
  } : {};
63
- let response = await this.requestApi(path, query, headers);
63
+ let response = await this.requestApi(path, query, headers, signal);
64
64
  for (; ; ) {
65
65
  if (response.status !== 200) {
66
66
  await this.handleError(path, response);
@@ -71,7 +71,12 @@ class MicrosoftGraphClient {
71
71
  if (!result["@odata.nextLink"]) {
72
72
  return;
73
73
  }
74
- response = await this.requestRaw(result["@odata.nextLink"], headers);
74
+ response = await this.requestRaw(
75
+ result["@odata.nextLink"],
76
+ headers,
77
+ 2,
78
+ signal
79
+ );
75
80
  }
76
81
  }
77
82
  /**
@@ -82,7 +87,7 @@ class MicrosoftGraphClient {
82
87
  * @param query - OData Query {@link ODataQuery}
83
88
  * @param headers - optional HTTP headers
84
89
  */
85
- async requestApi(path, query, headers) {
90
+ async requestApi(path, query, headers, signal) {
86
91
  const queryString = qs__default.default.stringify(
87
92
  {
88
93
  $search: query?.search,
@@ -99,7 +104,9 @@ class MicrosoftGraphClient {
99
104
  );
100
105
  return await this.requestRaw(
101
106
  `${this.baseUrl}/${path}${queryString}`,
102
- headers
107
+ headers,
108
+ 2,
109
+ signal
103
110
  );
104
111
  }
105
112
  /**
@@ -108,7 +115,7 @@ class MicrosoftGraphClient {
108
115
  * @param url - HTTP Endpoint of Graph API
109
116
  * @param headers - optional HTTP headers
110
117
  */
111
- async requestRaw(url, headers, retryCount = 2) {
118
+ async requestRaw(url, headers, retryCount = 2, signal) {
112
119
  const urlObj = new URL(url);
113
120
  const token = await this.tokenCredential.getToken(
114
121
  `${urlObj.protocol}//${urlObj.hostname}/.default`
@@ -121,11 +128,12 @@ class MicrosoftGraphClient {
121
128
  headers: {
122
129
  ...headers,
123
130
  Authorization: `Bearer ${token.token}`
124
- }
131
+ },
132
+ signal
125
133
  });
126
134
  } catch (e) {
127
135
  if (e?.code === "ETIMEDOUT" && retryCount > 0) {
128
- return this.requestRaw(url, headers, retryCount - 1);
136
+ return this.requestRaw(url, headers, retryCount - 1, signal);
129
137
  }
130
138
  throw e;
131
139
  }
@@ -154,8 +162,13 @@ class MicrosoftGraphClient {
154
162
  * @param queryMode - Mode to use while querying. Some features are only available at "advanced".
155
163
  * @param path - Resource endpoint in Microsoft Graph
156
164
  */
157
- async *getUsers(query, queryMode, path = "users") {
158
- yield* this.requestCollection(path, query, queryMode);
165
+ async *getUsers(query, queryMode, path = "users", signal) {
166
+ yield* this.requestCollection(
167
+ path,
168
+ query,
169
+ queryMode,
170
+ signal
171
+ );
159
172
  }
160
173
  /**
161
174
  * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto}
@@ -181,8 +194,13 @@ class MicrosoftGraphClient {
181
194
  * @param queryMode - Mode to use while querying. Some features are only available at "advanced".
182
195
  * @param path - Resource endpoint in Microsoft Graph
183
196
  */
184
- async *getGroups(query, queryMode, path = "groups") {
185
- yield* this.requestCollection(path, query, queryMode);
197
+ async *getGroups(query, queryMode, path = "groups", signal) {
198
+ yield* this.requestCollection(
199
+ path,
200
+ query,
201
+ queryMode,
202
+ signal
203
+ );
186
204
  }
187
205
  /**
188
206
  * Get a collection of
@@ -192,11 +210,12 @@ class MicrosoftGraphClient {
192
210
  * @param groupId - The unique identifier for the `Group` resource
193
211
  *
194
212
  */
195
- async *getGroupMembers(groupId, query, queryMode) {
213
+ async *getGroupMembers(groupId, query, queryMode, signal) {
196
214
  yield* this.requestCollection(
197
215
  `groups/${groupId}/members`,
198
216
  query,
199
- queryMode
217
+ queryMode,
218
+ signal
200
219
  );
201
220
  }
202
221
  /**
@@ -208,11 +227,12 @@ class MicrosoftGraphClient {
208
227
  * @param query - OData Query {@link ODataQuery}
209
228
  * @param queryMode - Mode to use while querying. Some features are only available at "advanced".
210
229
  */
211
- async *getGroupUserMembers(groupId, query, queryMode) {
230
+ async *getGroupUserMembers(groupId, query, queryMode, signal) {
212
231
  yield* this.requestCollection(
213
232
  `groups/${groupId}/members/microsoft.graph.user/`,
214
233
  query,
215
- queryMode
234
+ queryMode,
235
+ signal
216
236
  );
217
237
  }
218
238
  /**
@@ -222,8 +242,13 @@ class MicrosoftGraphClient {
222
242
  * @param tenantId - The unique identifier for the `Organization` resource
223
243
  *
224
244
  */
225
- async getOrganization(tenantId) {
226
- const response = await this.requestApi(`organization/${tenantId}`);
245
+ async getOrganization(tenantId, signal) {
246
+ const response = await this.requestApi(
247
+ `organization/${tenantId}`,
248
+ void 0,
249
+ void 0,
250
+ signal
251
+ );
227
252
  if (response.status !== 200) {
228
253
  await this.handleError(`organization/${tenantId}`, response);
229
254
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.cjs.js","sources":["../../src/microsoftGraph/client.ts"],"sourcesContent":["/*\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 TokenCredential,\n DefaultAzureCredential,\n ClientSecretCredential,\n} from '@azure/identity';\nimport * as MicrosoftGraph from '@microsoft/microsoft-graph-types';\nimport qs from 'qs';\nimport { MicrosoftGraphProviderConfig } from './config';\n\n/**\n * OData (Open Data Protocol) Query\n *\n * {@link https://docs.microsoft.com/en-us/odata/concepts/queryoptions-overview}\n * {@link https://docs.microsoft.com/en-us/graph/query-parameters}\n * @public\n */\nexport type ODataQuery = {\n /**\n * search resources within a collection matching a free-text search expression.\n */\n search?: string;\n /**\n * filter a collection of resources\n */\n filter?: string;\n /**\n * specifies the related resources or media streams to be included in line with retrieved resources\n */\n expand?: string;\n /**\n * request a specific set of properties for each entity or complex type\n */\n select?: string[];\n /**\n * Retrieves the total count of matching resources.\n */\n count?: boolean;\n /**\n * Maximum number of records to receive in one batch.\n */\n top?: number;\n};\n\n/**\n * Extends the base msgraph types to include the odata type.\n *\n * @public\n */\nexport type GroupMember =\n | (MicrosoftGraph.Group & { '@odata.type': '#microsoft.graph.group' })\n | (MicrosoftGraph.User & { '@odata.type': '#microsoft.graph.user' });\n\n/**\n * A HTTP Client that communicates with Microsoft Graph API.\n * Simplify Authentication and API calls to get `User` and `Group` from Microsoft Graph\n *\n * Uses `msal-node` for authentication\n *\n * @public\n */\nexport class MicrosoftGraphClient {\n /**\n * Factory method that instantiate `msal` client and return\n * an instance of `MicrosoftGraphClient`\n *\n * @public\n *\n * @param config - Configuration for Interacting with Graph API\n */\n static create(config: MicrosoftGraphProviderConfig): MicrosoftGraphClient {\n const options = {\n authorityHost: config.authority,\n tenantId: config.tenantId,\n };\n\n const credential =\n config.clientId && config.clientSecret\n ? new ClientSecretCredential(\n config.tenantId,\n config.clientId,\n config.clientSecret,\n options,\n )\n : new DefaultAzureCredential(options);\n\n return new MicrosoftGraphClient(config.target, credential);\n }\n\n /**\n * @param baseUrl - baseUrl of Graph API {@link MicrosoftGraphProviderConfig.target}\n * @param tokenCredential - instance of `TokenCredential` that is used to acquire token for Graph API calls\n *\n */\n private readonly baseUrl: string;\n private readonly tokenCredential: TokenCredential;\n\n constructor(baseUrl: string, tokenCredential: TokenCredential) {\n this.baseUrl = baseUrl;\n this.tokenCredential = tokenCredential;\n }\n\n /**\n * Get a collection of resource from Graph API and\n * return an `AsyncIterable` of that resource\n *\n * @public\n * @param path - Resource in Microsoft Graph\n * @param query - OData Query {@link ODataQuery}\n * @param queryMode - Mode to use while querying. Some features are only available at \"advanced\".\n */\n async *requestCollection<T>(\n path: string,\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n ): AsyncIterable<T> {\n // upgrade to advanced query mode transparently when \"search\" is used\n // to stay backwards compatible.\n const appliedQueryMode = query?.search ? 'advanced' : queryMode ?? 'basic';\n\n // not needed for \"search\"\n // as of https://docs.microsoft.com/en-us/graph/aad-advanced-queries?tabs=http\n // even though a few other places say the opposite\n // - https://docs.microsoft.com/en-us/graph/api/user-list?view=graph-rest-1.0&tabs=http#request-headers\n // - https://docs.microsoft.com/en-us/graph/api/resources/group?view=graph-rest-1.0#properties\n if (appliedQueryMode === 'advanced' && (query?.filter || query?.select)) {\n query.count = true;\n }\n const headers: Record<string, string> =\n appliedQueryMode === 'advanced'\n ? {\n // Eventual consistency is required for advanced querying capabilities\n // like \"$search\" or parts of \"$filter\".\n // If a new user/group is not found, it'll eventually be imported on a subsequent read\n ConsistencyLevel: 'eventual',\n }\n : {};\n\n let response = await this.requestApi(path, query, headers);\n\n for (;;) {\n if (response.status !== 200) {\n await this.handleError(path, response);\n }\n\n const result = await response.json();\n\n // Graph API return array of collections\n const elements: T[] = result.value;\n\n yield* elements;\n\n // Follow cursor to the next page if one is available\n if (!result['@odata.nextLink']) {\n return;\n }\n\n response = await this.requestRaw(result['@odata.nextLink'], headers);\n }\n }\n\n /**\n * Abstract on top of {@link MicrosoftGraphClient.requestRaw}\n *\n * @public\n * @param path - Resource in Microsoft Graph\n * @param query - OData Query {@link ODataQuery}\n * @param headers - optional HTTP headers\n */\n async requestApi(\n path: string,\n query?: ODataQuery,\n headers?: Record<string, string>,\n ): Promise<Response> {\n const queryString = qs.stringify(\n {\n $search: query?.search,\n $filter: query?.filter,\n $select: query?.select?.join(','),\n $expand: query?.expand,\n $count: query?.count,\n $top: query?.top,\n },\n {\n addQueryPrefix: true,\n encode: true,\n },\n );\n\n return await this.requestRaw(\n `${this.baseUrl}/${path}${queryString}`,\n headers,\n );\n }\n\n /**\n * Makes a HTTP call to Graph API with token\n *\n * @param url - HTTP Endpoint of Graph API\n * @param headers - optional HTTP headers\n */\n async requestRaw(\n url: string,\n headers?: Record<string, string>,\n retryCount = 2,\n ): Promise<Response> {\n // Make sure that we always have a valid access token (might be cached)\n const urlObj = new URL(url);\n const token = await this.tokenCredential.getToken(\n `${urlObj.protocol}//${urlObj.hostname}/.default`,\n );\n\n if (!token) {\n throw new Error('Failed to obtain token from Azure Identity');\n }\n\n try {\n return await fetch(url, {\n headers: {\n ...headers,\n Authorization: `Bearer ${token.token}`,\n },\n });\n } catch (e: any) {\n if (e?.code === 'ETIMEDOUT' && retryCount > 0) {\n return this.requestRaw(url, headers, retryCount - 1);\n }\n throw e;\n }\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto}\n * of `User` from Graph API with size limit\n *\n * @param userId - The unique identifier for the `User` resource\n * @param maxSize - Maximum pixel height of the photo\n *\n */\n async getUserPhotoWithSizeLimit(\n userId: string,\n maxSize: number,\n ): Promise<string | undefined> {\n return await this.getPhotoWithSizeLimit('users', userId, maxSize);\n }\n\n async getUserPhoto(\n userId: string,\n sizeId?: string,\n ): Promise<string | undefined> {\n return await this.getPhoto('users', userId, sizeId);\n }\n\n /**\n * Get a collection of\n * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User}\n * from Graph API and return as `AsyncIterable`\n *\n * @public\n * @param query - OData Query {@link ODataQuery}\n * @param queryMode - Mode to use while querying. Some features are only available at \"advanced\".\n * @param path - Resource endpoint in Microsoft Graph\n */\n async *getUsers(\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n path: string = 'users',\n ): AsyncIterable<MicrosoftGraph.User> {\n yield* this.requestCollection<MicrosoftGraph.User>(path, query, queryMode);\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto}\n * of `Group` from Graph API with size limit\n *\n * @param groupId - The unique identifier for the `Group` resource\n * @param maxSize - Maximum pixel height of the photo\n *\n */\n async getGroupPhotoWithSizeLimit(\n groupId: string,\n maxSize: number,\n ): Promise<string | undefined> {\n return await this.getPhotoWithSizeLimit('groups', groupId, maxSize);\n }\n\n async getGroupPhoto(\n groupId: string,\n sizeId?: string,\n ): Promise<string | undefined> {\n return await this.getPhoto('groups', groupId, sizeId);\n }\n\n /**\n * Get a collection of\n * {@link https://docs.microsoft.com/en-us/graph/api/resources/group | Group}\n * from Graph API and return as `AsyncIterable`\n *\n * @public\n * @param query - OData Query {@link ODataQuery}\n * @param queryMode - Mode to use while querying. Some features are only available at \"advanced\".\n * @param path - Resource endpoint in Microsoft Graph\n */\n async *getGroups(\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n path: string = 'groups',\n ): AsyncIterable<MicrosoftGraph.Group> {\n yield* this.requestCollection<MicrosoftGraph.Group>(path, query, queryMode);\n }\n\n /**\n * Get a collection of\n * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User}\n * belonging to a `Group` from Graph API and return as `AsyncIterable`\n * @public\n * @param groupId - The unique identifier for the `Group` resource\n *\n */\n async *getGroupMembers(\n groupId: string,\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n ): AsyncIterable<GroupMember> {\n yield* this.requestCollection<GroupMember>(\n `groups/${groupId}/members`,\n query,\n queryMode,\n );\n }\n\n /**\n * Get a collection of\n * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User}\n * belonging to a `Group` from Graph API and return as `AsyncIterable`\n * @public\n * @param groupId - The unique identifier for the `Group` resource\n * @param query - OData Query {@link ODataQuery}\n * @param queryMode - Mode to use while querying. Some features are only available at \"advanced\".\n */\n async *getGroupUserMembers(\n groupId: string,\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n ): AsyncIterable<MicrosoftGraph.User> {\n yield* this.requestCollection<MicrosoftGraph.User>(\n `groups/${groupId}/members/microsoft.graph.user/`,\n query,\n queryMode,\n );\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/organization | Organization}\n * from Graph API\n * @public\n * @param tenantId - The unique identifier for the `Organization` resource\n *\n */\n async getOrganization(\n tenantId: string,\n ): Promise<MicrosoftGraph.Organization> {\n const response = await this.requestApi(`organization/${tenantId}`);\n\n if (response.status !== 200) {\n await this.handleError(`organization/${tenantId}`, response);\n }\n\n return await response.json();\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto}\n * from Graph API\n *\n * @param entityName - type of parent resource, either `User` or `Group`\n * @param id - The unique identifier for the `entityName` resource\n * @param maxSize - Maximum pixel height of the photo\n *\n */\n private async getPhotoWithSizeLimit(\n entityName: string,\n id: string,\n maxSize: number,\n ): Promise<string | undefined> {\n const response = await this.requestApi(`${entityName}/${id}/photos`);\n\n if (response.status === 404) {\n return undefined;\n } else if (response.status !== 200) {\n await this.handleError(`${entityName} photos`, response);\n }\n\n const result = await response.json();\n const photos = result.value as MicrosoftGraph.ProfilePhoto[];\n let selectedPhoto: MicrosoftGraph.ProfilePhoto | undefined = undefined;\n\n // Find the biggest picture that is smaller than the max size\n for (const p of photos) {\n if (\n !selectedPhoto ||\n (p.height! >= selectedPhoto.height! && p.height! <= maxSize)\n ) {\n selectedPhoto = p;\n }\n }\n\n if (!selectedPhoto) {\n return undefined;\n }\n\n return await this.getPhoto(entityName, id, selectedPhoto.id!);\n }\n\n private async getPhoto(\n entityName: string,\n id: string,\n sizeId?: string,\n ): Promise<string | undefined> {\n const path = sizeId\n ? `${entityName}/${id}/photos/${sizeId}/$value`\n : `${entityName}/${id}/photo/$value`;\n const response = await this.requestApi(path);\n\n if (response.status === 404) {\n return undefined;\n } else if (response.status !== 200) {\n await this.handleError('photo', response);\n }\n\n return `data:image/jpeg;base64,${Buffer.from(\n await response.arrayBuffer(),\n ).toString('base64')}`;\n }\n\n private async handleError(path: string, response: Response): Promise<void> {\n const result = await response.json();\n const error = result.error as MicrosoftGraph.PublicError;\n\n throw new Error(\n `Error while reading ${path} from Microsoft Graph: ${error.code} - ${error.message}`,\n );\n }\n}\n"],"names":["ClientSecretCredential","DefaultAzureCredential","qs"],"mappings":"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"}
1
+ {"version":3,"file":"client.cjs.js","sources":["../../src/microsoftGraph/client.ts"],"sourcesContent":["/*\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 TokenCredential,\n DefaultAzureCredential,\n ClientSecretCredential,\n} from '@azure/identity';\nimport * as MicrosoftGraph from '@microsoft/microsoft-graph-types';\nimport qs from 'qs';\nimport { MicrosoftGraphProviderConfig } from './config';\n\n/**\n * OData (Open Data Protocol) Query\n *\n * {@link https://docs.microsoft.com/en-us/odata/concepts/queryoptions-overview}\n * {@link https://docs.microsoft.com/en-us/graph/query-parameters}\n * @public\n */\nexport type ODataQuery = {\n /**\n * search resources within a collection matching a free-text search expression.\n */\n search?: string;\n /**\n * filter a collection of resources\n */\n filter?: string;\n /**\n * specifies the related resources or media streams to be included in line with retrieved resources\n */\n expand?: string;\n /**\n * request a specific set of properties for each entity or complex type\n */\n select?: string[];\n /**\n * Retrieves the total count of matching resources.\n */\n count?: boolean;\n /**\n * Maximum number of records to receive in one batch.\n */\n top?: number;\n};\n\n/**\n * Extends the base msgraph types to include the odata type.\n *\n * @public\n */\nexport type GroupMember =\n | (MicrosoftGraph.Group & { '@odata.type': '#microsoft.graph.group' })\n | (MicrosoftGraph.User & { '@odata.type': '#microsoft.graph.user' });\n\n/**\n * A HTTP Client that communicates with Microsoft Graph API.\n * Simplify Authentication and API calls to get `User` and `Group` from Microsoft Graph\n *\n * Uses `msal-node` for authentication\n *\n * @public\n */\nexport class MicrosoftGraphClient {\n /**\n * Factory method that instantiate `msal` client and return\n * an instance of `MicrosoftGraphClient`\n *\n * @public\n *\n * @param config - Configuration for Interacting with Graph API\n */\n static create(config: MicrosoftGraphProviderConfig): MicrosoftGraphClient {\n const options = {\n authorityHost: config.authority,\n tenantId: config.tenantId,\n };\n\n const credential =\n config.clientId && config.clientSecret\n ? new ClientSecretCredential(\n config.tenantId,\n config.clientId,\n config.clientSecret,\n options,\n )\n : new DefaultAzureCredential(options);\n\n return new MicrosoftGraphClient(config.target, credential);\n }\n\n /**\n * @param baseUrl - baseUrl of Graph API {@link MicrosoftGraphProviderConfig.target}\n * @param tokenCredential - instance of `TokenCredential` that is used to acquire token for Graph API calls\n *\n */\n private readonly baseUrl: string;\n private readonly tokenCredential: TokenCredential;\n\n constructor(baseUrl: string, tokenCredential: TokenCredential) {\n this.baseUrl = baseUrl;\n this.tokenCredential = tokenCredential;\n }\n\n /**\n * Get a collection of resource from Graph API and\n * return an `AsyncIterable` of that resource\n *\n * @public\n * @param path - Resource in Microsoft Graph\n * @param query - OData Query {@link ODataQuery}\n * @param queryMode - Mode to use while querying. Some features are only available at \"advanced\".\n */\n async *requestCollection<T>(\n path: string,\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n signal?: AbortSignal,\n ): AsyncIterable<T> {\n // upgrade to advanced query mode transparently when \"search\" is used\n // to stay backwards compatible.\n const appliedQueryMode = query?.search ? 'advanced' : queryMode ?? 'basic';\n\n // not needed for \"search\"\n // as of https://docs.microsoft.com/en-us/graph/aad-advanced-queries?tabs=http\n // even though a few other places say the opposite\n // - https://docs.microsoft.com/en-us/graph/api/user-list?view=graph-rest-1.0&tabs=http#request-headers\n // - https://docs.microsoft.com/en-us/graph/api/resources/group?view=graph-rest-1.0#properties\n if (appliedQueryMode === 'advanced' && (query?.filter || query?.select)) {\n query.count = true;\n }\n const headers: Record<string, string> =\n appliedQueryMode === 'advanced'\n ? {\n // Eventual consistency is required for advanced querying capabilities\n // like \"$search\" or parts of \"$filter\".\n // If a new user/group is not found, it'll eventually be imported on a subsequent read\n ConsistencyLevel: 'eventual',\n }\n : {};\n\n let response = await this.requestApi(path, query, headers, signal);\n\n for (;;) {\n if (response.status !== 200) {\n await this.handleError(path, response);\n }\n\n const result = await response.json();\n\n // Graph API return array of collections\n const elements: T[] = result.value;\n\n yield* elements;\n\n // Follow cursor to the next page if one is available\n if (!result['@odata.nextLink']) {\n return;\n }\n\n response = await this.requestRaw(\n result['@odata.nextLink'],\n headers,\n 2,\n signal,\n );\n }\n }\n\n /**\n * Abstract on top of {@link MicrosoftGraphClient.requestRaw}\n *\n * @public\n * @param path - Resource in Microsoft Graph\n * @param query - OData Query {@link ODataQuery}\n * @param headers - optional HTTP headers\n */\n async requestApi(\n path: string,\n query?: ODataQuery,\n headers?: Record<string, string>,\n signal?: AbortSignal,\n ): Promise<Response> {\n const queryString = qs.stringify(\n {\n $search: query?.search,\n $filter: query?.filter,\n $select: query?.select?.join(','),\n $expand: query?.expand,\n $count: query?.count,\n $top: query?.top,\n },\n {\n addQueryPrefix: true,\n encode: true,\n },\n );\n\n return await this.requestRaw(\n `${this.baseUrl}/${path}${queryString}`,\n headers,\n 2,\n signal,\n );\n }\n\n /**\n * Makes a HTTP call to Graph API with token\n *\n * @param url - HTTP Endpoint of Graph API\n * @param headers - optional HTTP headers\n */\n async requestRaw(\n url: string,\n headers?: Record<string, string>,\n retryCount = 2,\n signal?: AbortSignal,\n ): Promise<Response> {\n // Make sure that we always have a valid access token (might be cached)\n const urlObj = new URL(url);\n const token = await this.tokenCredential.getToken(\n `${urlObj.protocol}//${urlObj.hostname}/.default`,\n );\n\n if (!token) {\n throw new Error('Failed to obtain token from Azure Identity');\n }\n\n try {\n return await fetch(url, {\n headers: {\n ...headers,\n Authorization: `Bearer ${token.token}`,\n },\n signal,\n });\n } catch (e: any) {\n if (e?.code === 'ETIMEDOUT' && retryCount > 0) {\n return this.requestRaw(url, headers, retryCount - 1, signal);\n }\n throw e;\n }\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto}\n * of `User` from Graph API with size limit\n *\n * @param userId - The unique identifier for the `User` resource\n * @param maxSize - Maximum pixel height of the photo\n *\n */\n async getUserPhotoWithSizeLimit(\n userId: string,\n maxSize: number,\n ): Promise<string | undefined> {\n return await this.getPhotoWithSizeLimit('users', userId, maxSize);\n }\n\n async getUserPhoto(\n userId: string,\n sizeId?: string,\n ): Promise<string | undefined> {\n return await this.getPhoto('users', userId, sizeId);\n }\n\n /**\n * Get a collection of\n * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User}\n * from Graph API and return as `AsyncIterable`\n *\n * @public\n * @param query - OData Query {@link ODataQuery}\n * @param queryMode - Mode to use while querying. Some features are only available at \"advanced\".\n * @param path - Resource endpoint in Microsoft Graph\n */\n async *getUsers(\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n path: string = 'users',\n signal?: AbortSignal,\n ): AsyncIterable<MicrosoftGraph.User> {\n yield* this.requestCollection<MicrosoftGraph.User>(\n path,\n query,\n queryMode,\n signal,\n );\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto}\n * of `Group` from Graph API with size limit\n *\n * @param groupId - The unique identifier for the `Group` resource\n * @param maxSize - Maximum pixel height of the photo\n *\n */\n async getGroupPhotoWithSizeLimit(\n groupId: string,\n maxSize: number,\n ): Promise<string | undefined> {\n return await this.getPhotoWithSizeLimit('groups', groupId, maxSize);\n }\n\n async getGroupPhoto(\n groupId: string,\n sizeId?: string,\n ): Promise<string | undefined> {\n return await this.getPhoto('groups', groupId, sizeId);\n }\n\n /**\n * Get a collection of\n * {@link https://docs.microsoft.com/en-us/graph/api/resources/group | Group}\n * from Graph API and return as `AsyncIterable`\n *\n * @public\n * @param query - OData Query {@link ODataQuery}\n * @param queryMode - Mode to use while querying. Some features are only available at \"advanced\".\n * @param path - Resource endpoint in Microsoft Graph\n */\n async *getGroups(\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n path: string = 'groups',\n signal?: AbortSignal,\n ): AsyncIterable<MicrosoftGraph.Group> {\n yield* this.requestCollection<MicrosoftGraph.Group>(\n path,\n query,\n queryMode,\n signal,\n );\n }\n\n /**\n * Get a collection of\n * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User}\n * belonging to a `Group` from Graph API and return as `AsyncIterable`\n * @public\n * @param groupId - The unique identifier for the `Group` resource\n *\n */\n async *getGroupMembers(\n groupId: string,\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n signal?: AbortSignal,\n ): AsyncIterable<GroupMember> {\n yield* this.requestCollection<GroupMember>(\n `groups/${groupId}/members`,\n query,\n queryMode,\n signal,\n );\n }\n\n /**\n * Get a collection of\n * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User}\n * belonging to a `Group` from Graph API and return as `AsyncIterable`\n * @public\n * @param groupId - The unique identifier for the `Group` resource\n * @param query - OData Query {@link ODataQuery}\n * @param queryMode - Mode to use while querying. Some features are only available at \"advanced\".\n */\n async *getGroupUserMembers(\n groupId: string,\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n signal?: AbortSignal,\n ): AsyncIterable<MicrosoftGraph.User> {\n yield* this.requestCollection<MicrosoftGraph.User>(\n `groups/${groupId}/members/microsoft.graph.user/`,\n query,\n queryMode,\n signal,\n );\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/organization | Organization}\n * from Graph API\n * @public\n * @param tenantId - The unique identifier for the `Organization` resource\n *\n */\n async getOrganization(\n tenantId: string,\n signal?: AbortSignal,\n ): Promise<MicrosoftGraph.Organization> {\n const response = await this.requestApi(\n `organization/${tenantId}`,\n undefined,\n undefined,\n signal,\n );\n\n if (response.status !== 200) {\n await this.handleError(`organization/${tenantId}`, response);\n }\n\n return await response.json();\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto}\n * from Graph API\n *\n * @param entityName - type of parent resource, either `User` or `Group`\n * @param id - The unique identifier for the `entityName` resource\n * @param maxSize - Maximum pixel height of the photo\n *\n */\n private async getPhotoWithSizeLimit(\n entityName: string,\n id: string,\n maxSize: number,\n ): Promise<string | undefined> {\n const response = await this.requestApi(`${entityName}/${id}/photos`);\n\n if (response.status === 404) {\n return undefined;\n } else if (response.status !== 200) {\n await this.handleError(`${entityName} photos`, response);\n }\n\n const result = await response.json();\n const photos = result.value as MicrosoftGraph.ProfilePhoto[];\n let selectedPhoto: MicrosoftGraph.ProfilePhoto | undefined = undefined;\n\n // Find the biggest picture that is smaller than the max size\n for (const p of photos) {\n if (\n !selectedPhoto ||\n (p.height! >= selectedPhoto.height! && p.height! <= maxSize)\n ) {\n selectedPhoto = p;\n }\n }\n\n if (!selectedPhoto) {\n return undefined;\n }\n\n return await this.getPhoto(entityName, id, selectedPhoto.id!);\n }\n\n private async getPhoto(\n entityName: string,\n id: string,\n sizeId?: string,\n ): Promise<string | undefined> {\n const path = sizeId\n ? `${entityName}/${id}/photos/${sizeId}/$value`\n : `${entityName}/${id}/photo/$value`;\n const response = await this.requestApi(path);\n\n if (response.status === 404) {\n return undefined;\n } else if (response.status !== 200) {\n await this.handleError('photo', response);\n }\n\n return `data:image/jpeg;base64,${Buffer.from(\n await response.arrayBuffer(),\n ).toString('base64')}`;\n }\n\n private async handleError(path: string, response: Response): Promise<void> {\n const result = await response.json();\n const error = result.error as MicrosoftGraph.PublicError;\n\n throw new Error(\n `Error while reading ${path} from Microsoft Graph: ${error.code} - ${error.message}`,\n );\n }\n}\n"],"names":["ClientSecretCredential","DefaultAzureCredential","qs"],"mappings":"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"}
@@ -20,7 +20,8 @@ async function readMicrosoftGraphUsers(client, options) {
20
20
  top: PAGE_SIZE
21
21
  },
22
22
  options.queryMode,
23
- options.userPath
23
+ options.userPath,
24
+ options.signal
24
25
  );
25
26
  return {
26
27
  users: await transformUsers(
@@ -45,7 +46,8 @@ async function readMicrosoftGraphUsersInGroups(client, options) {
45
46
  top: PAGE_SIZE
46
47
  },
47
48
  options.queryMode,
48
- options.userGroupMemberPath
49
+ options.userGroupMemberPath,
50
+ options.signal
49
51
  )) {
50
52
  userGroupMemberPromises.push(
51
53
  limiter(async () => {
@@ -58,7 +60,8 @@ async function readMicrosoftGraphUsersInGroups(client, options) {
58
60
  select: options.userSelect,
59
61
  top: PAGE_SIZE
60
62
  },
61
- options.queryMode
63
+ options.queryMode,
64
+ options.signal
62
65
  )) {
63
66
  userGroupMembers.set(user.id, user);
64
67
  groupMemberCount++;
@@ -87,7 +90,7 @@ async function readMicrosoftGraphUsersInGroups(client, options) {
87
90
  };
88
91
  }
89
92
  async function readMicrosoftGraphOrganization(client, tenantId, options) {
90
- const organization = await client.getOrganization(tenantId);
93
+ const organization = await client.getOrganization(tenantId, options?.signal);
91
94
  const transformer = options?.transformer ?? defaultTransformers.defaultOrganizationTransformer;
92
95
  const rootGroup = await transformer(organization);
93
96
  return { rootGroup };
@@ -98,7 +101,8 @@ async function readMicrosoftGraphGroups(client, tenantId, options) {
98
101
  const groupMemberOf = /* @__PURE__ */ new Map();
99
102
  const limiter = limiterFactory__default.default(10);
100
103
  const { rootGroup } = await readMicrosoftGraphOrganization(client, tenantId, {
101
- transformer: options?.organizationTransformer
104
+ transformer: options?.organizationTransformer,
105
+ signal: options?.signal
102
106
  });
103
107
  if (rootGroup) {
104
108
  groupMember.set(rootGroup.metadata.name, /* @__PURE__ */ new Set());
@@ -115,7 +119,8 @@ async function readMicrosoftGraphGroups(client, tenantId, options) {
115
119
  top: PAGE_SIZE
116
120
  },
117
121
  options?.queryMode,
118
- options?.groupPath
122
+ options?.groupPath,
123
+ options?.signal
119
124
  )) {
120
125
  promises.push(
121
126
  limiter(async () => {
@@ -126,9 +131,14 @@ async function readMicrosoftGraphGroups(client, tenantId, options) {
126
131
  if (!entity) {
127
132
  return;
128
133
  }
129
- for await (const member of client.getGroupMembers(group.id, {
130
- top: PAGE_SIZE
131
- })) {
134
+ for await (const member of client.getGroupMembers(
135
+ group.id,
136
+ {
137
+ top: PAGE_SIZE
138
+ },
139
+ void 0,
140
+ options?.signal
141
+ )) {
132
142
  if (!member.id) {
133
143
  continue;
134
144
  }
@@ -143,7 +153,9 @@ async function readMicrosoftGraphGroups(client, tenantId, options) {
143
153
  groups.push(groupMemberEntity);
144
154
  for await (const subMember of client.getGroupMembers(
145
155
  member.id,
146
- { top: PAGE_SIZE }
156
+ { top: PAGE_SIZE },
157
+ void 0,
158
+ options?.signal
147
159
  )) {
148
160
  if (!subMember.id) {
149
161
  continue;
@@ -252,7 +264,8 @@ async function readMicrosoftGraphOrg(client, tenantId, options) {
252
264
  userGroupMemberPath: options.userGroupMemberPath,
253
265
  loadUserPhotos: options.loadUserPhotos,
254
266
  transformer: options.userTransformer,
255
- logger: options.logger
267
+ logger: options.logger,
268
+ signal: options.signal
256
269
  }
257
270
  );
258
271
  users = usersInGroups;
@@ -265,7 +278,8 @@ async function readMicrosoftGraphOrg(client, tenantId, options) {
265
278
  userPath: options.userPath,
266
279
  loadUserPhotos: options.loadUserPhotos,
267
280
  transformer: options.userTransformer,
268
- logger: options.logger
281
+ logger: options.logger,
282
+ signal: options.signal
269
283
  });
270
284
  users = usersWithFilter;
271
285
  }
@@ -278,7 +292,8 @@ async function readMicrosoftGraphOrg(client, tenantId, options) {
278
292
  groupPath: options.groupPath,
279
293
  groupIncludeSubGroups: options.groupIncludeSubGroups,
280
294
  groupTransformer: options.groupTransformer,
281
- organizationTransformer: options.organizationTransformer
295
+ organizationTransformer: options.organizationTransformer,
296
+ signal: options.signal
282
297
  });
283
298
  resolveRelations(rootGroup, groups, users, groupMember, groupMemberOf);
284
299
  users.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));
@@ -1 +1 @@
1
- {"version":3,"file":"read.cjs.js","sources":["../../src/microsoftGraph/read.ts"],"sourcesContent":["/*\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 GroupEntity,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport limiterFactory from 'p-limit';\nimport { MicrosoftGraphClient } from './client';\nimport {\n MICROSOFT_GRAPH_GROUP_ID_ANNOTATION,\n MICROSOFT_GRAPH_TENANT_ID_ANNOTATION,\n MICROSOFT_GRAPH_USER_ID_ANNOTATION,\n} from './constants';\nimport { buildMemberOf, buildOrgHierarchy } from './org';\nimport {\n GroupTransformer,\n OrganizationTransformer,\n UserTransformer,\n} from './types';\nimport {\n defaultGroupTransformer,\n defaultOrganizationTransformer,\n defaultUserTransformer,\n} from './defaultTransformers';\nimport * as MicrosoftGraph from '@microsoft/microsoft-graph-types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst PAGE_SIZE = 999;\n\nexport async function readMicrosoftGraphUsers(\n client: MicrosoftGraphClient,\n options: {\n queryMode?: 'basic' | 'advanced';\n userExpand?: string;\n userFilter?: string;\n userSelect?: string[];\n userPath?: string;\n loadUserPhotos?: boolean;\n transformer?: UserTransformer;\n logger: LoggerService;\n },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n}> {\n const users = client.getUsers(\n {\n filter: options.userFilter,\n expand: options.userExpand,\n select: options.userSelect,\n top: PAGE_SIZE,\n },\n options.queryMode,\n options.userPath,\n );\n\n return {\n users: await transformUsers(\n client,\n users,\n options.logger,\n options.loadUserPhotos,\n options.transformer,\n ),\n };\n}\n\nexport async function readMicrosoftGraphUsersInGroups(\n client: MicrosoftGraphClient,\n options: {\n queryMode?: 'basic' | 'advanced';\n userExpand?: string;\n userFilter?: string;\n userSelect?: string[];\n loadUserPhotos?: boolean;\n userGroupMemberSearch?: string;\n userGroupMemberFilter?: string;\n userGroupMemberPath?: string;\n groupExpand?: string;\n transformer?: UserTransformer;\n logger: LoggerService;\n },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n}> {\n const limiter = limiterFactory(10);\n\n const userGroupMemberPromises: Promise<void>[] = [];\n const userGroupMembers = new Map<string, MicrosoftGraph.User>();\n\n for await (const group of client.getGroups(\n {\n expand: options.groupExpand,\n filter: options.userGroupMemberFilter,\n search: options.userGroupMemberSearch,\n select: ['id', 'displayName'],\n top: PAGE_SIZE,\n },\n options.queryMode,\n options.userGroupMemberPath,\n )) {\n // Process all groups in parallel, otherwise it can take quite some time\n userGroupMemberPromises.push(\n limiter(async () => {\n let groupMemberCount = 0;\n for await (const user of client.getGroupUserMembers(\n group.id!,\n {\n expand: options.userExpand,\n filter: options.userFilter,\n select: options.userSelect,\n top: PAGE_SIZE,\n },\n options.queryMode,\n )) {\n userGroupMembers.set(user.id!, user);\n groupMemberCount++;\n }\n options.logger.debug('Read users from group', {\n groupId: group.id,\n groupName: group.displayName,\n memberCount: groupMemberCount,\n });\n }),\n );\n }\n\n // Wait for all group members\n await Promise.all(userGroupMemberPromises);\n\n options.logger.info('Read users from group membership', {\n groupCount: userGroupMemberPromises.length,\n userCount: userGroupMembers.size,\n });\n\n return {\n users: await transformUsers(\n client,\n userGroupMembers.values(),\n options.logger,\n options.loadUserPhotos,\n options.transformer,\n ),\n };\n}\n\nexport async function readMicrosoftGraphOrganization(\n client: MicrosoftGraphClient,\n tenantId: string,\n options?: { transformer?: OrganizationTransformer },\n): Promise<{\n rootGroup?: GroupEntity; // With all relations empty\n}> {\n // For now we expect a single root organization\n const organization = await client.getOrganization(tenantId);\n const transformer = options?.transformer ?? defaultOrganizationTransformer;\n const rootGroup = await transformer(organization);\n\n return { rootGroup };\n}\n\nexport async function readMicrosoftGraphGroups(\n client: MicrosoftGraphClient,\n tenantId: string,\n options?: {\n queryMode?: 'basic' | 'advanced';\n groupExpand?: string;\n groupFilter?: string;\n groupSearch?: string;\n groupSelect?: string[];\n groupPath?: string;\n groupIncludeSubGroups?: boolean;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n },\n): Promise<{\n groups: GroupEntity[]; // With all relations empty\n rootGroup: GroupEntity | undefined; // With all relations empty\n groupMember: Map<string, Set<string>>;\n groupMemberOf: Map<string, Set<string>>;\n}> {\n const groups: GroupEntity[] = [];\n const groupMember: Map<string, Set<string>> = new Map();\n const groupMemberOf: Map<string, Set<string>> = new Map();\n const limiter = limiterFactory(10);\n\n const { rootGroup } = await readMicrosoftGraphOrganization(client, tenantId, {\n transformer: options?.organizationTransformer,\n });\n if (rootGroup) {\n groupMember.set(rootGroup.metadata.name, new Set<string>());\n groups.push(rootGroup);\n }\n\n const transformer = options?.groupTransformer ?? defaultGroupTransformer;\n const promises: Promise<void>[] = [];\n\n for await (const group of client.getGroups(\n {\n expand: options?.groupExpand,\n filter: options?.groupFilter,\n search: options?.groupSearch,\n select: options?.groupSelect,\n top: PAGE_SIZE,\n },\n options?.queryMode,\n options?.groupPath,\n )) {\n // Process all groups in parallel, otherwise it can take quite some time\n promises.push(\n limiter(async () => {\n // TODO: Loading groups photos doesn't work right now as Microsoft Graph\n // doesn't allows this yet: https://microsoftgraph.uservoice.com/forums/920506-microsoft-graph-feature-requests/suggestions/37884922-allow-application-to-set-or-update-a-group-s-photo\n /* const groupPhoto = await client.getGroupPhotoWithSizeLimit(\n group.id!,\n // We are limiting the photo size, as groups with full resolution photos\n // can make the Backstage API slow\n 120,\n );*/\n\n const entity = await transformer(group /* , groupPhoto*/);\n\n if (!entity) {\n return;\n }\n\n for await (const member of client.getGroupMembers(group.id!, {\n top: PAGE_SIZE,\n })) {\n if (!member.id) {\n continue;\n }\n\n if (member['@odata.type'] === '#microsoft.graph.user') {\n ensureItem(groupMemberOf, member.id, group.id!);\n }\n\n if (member['@odata.type'] === '#microsoft.graph.group') {\n ensureItem(groupMember, group.id!, member.id);\n\n if (options?.groupIncludeSubGroups) {\n const groupMemberEntity = await transformer(member);\n\n if (groupMemberEntity) {\n groups.push(groupMemberEntity);\n\n for await (const subMember of client.getGroupMembers(\n member.id!,\n { top: PAGE_SIZE },\n )) {\n if (!subMember.id) {\n continue;\n }\n\n if (subMember['@odata.type'] === '#microsoft.graph.user') {\n ensureItem(groupMemberOf, subMember.id, member.id!);\n }\n\n if (subMember['@odata.type'] === '#microsoft.graph.group') {\n ensureItem(groupMember, member.id!, subMember.id);\n }\n }\n }\n }\n }\n }\n\n groups.push(entity);\n }),\n );\n }\n\n // Wait for all group members and photos to be loaded\n await Promise.all(promises);\n\n return {\n groups,\n rootGroup,\n groupMember,\n groupMemberOf,\n };\n}\n\nexport function resolveRelations(\n rootGroup: GroupEntity | undefined,\n groups: GroupEntity[],\n users: UserEntity[],\n groupMember: Map<string, Set<string>>,\n groupMemberOf: Map<string, Set<string>>,\n) {\n // Build reference lookup tables, we reference them by the id of the graph\n const groupMap: Map<string, GroupEntity> = new Map(); // by group-id or tenant-id\n\n for (const group of groups) {\n if (group.metadata.annotations![MICROSOFT_GRAPH_GROUP_ID_ANNOTATION]) {\n groupMap.set(\n group.metadata.annotations![MICROSOFT_GRAPH_GROUP_ID_ANNOTATION],\n group,\n );\n }\n if (group.metadata.annotations![MICROSOFT_GRAPH_TENANT_ID_ANNOTATION]) {\n groupMap.set(\n group.metadata.annotations![MICROSOFT_GRAPH_TENANT_ID_ANNOTATION],\n group,\n );\n }\n }\n\n // Resolve all member relationships into the reverse direction\n const parentGroups = new Map<string, Set<string>>();\n\n groupMember.forEach((members, groupId) =>\n members.forEach(m => ensureItem(parentGroups, m, groupId)),\n );\n\n // Make sure every group (except root) has at least one parent. If the parent is missing, add the root.\n if (rootGroup) {\n const tenantId =\n rootGroup.metadata.annotations![MICROSOFT_GRAPH_TENANT_ID_ANNOTATION];\n\n groups.forEach(group => {\n const groupId =\n group.metadata.annotations![MICROSOFT_GRAPH_GROUP_ID_ANNOTATION];\n\n if (!groupId) {\n return;\n }\n\n if (retrieveItems(parentGroups, groupId).size === 0) {\n ensureItem(parentGroups, groupId, tenantId);\n ensureItem(groupMember, tenantId, groupId);\n }\n });\n }\n\n groups.forEach(group => {\n const id =\n group.metadata.annotations![MICROSOFT_GRAPH_GROUP_ID_ANNOTATION] ??\n group.metadata.annotations![MICROSOFT_GRAPH_TENANT_ID_ANNOTATION];\n\n retrieveItems(groupMember, id).forEach(m => {\n const childGroup = groupMap.get(m);\n if (childGroup) {\n group.spec.children.push(stringifyEntityRef(childGroup));\n }\n });\n\n // TODO: Until we have better support for multiple parents in the model,\n // the order of the parents is important as changing it causes\n // unnecessary entity stitching randomly.\n retrieveItems(parentGroups, id).forEach(p => {\n // Only set the parent if it doesn't exist yet\n if (group.spec.parent) {\n return;\n }\n const parentGroup = groupMap.get(p);\n if (parentGroup) {\n // TODO: Only having a single parent group might not match every companies model, but fine for now.\n group.spec.parent = stringifyEntityRef(parentGroup);\n }\n });\n });\n\n // Make sure that all groups have proper parents and children\n buildOrgHierarchy(groups);\n\n // Set relations for all users\n users.forEach(user => {\n const id = user.metadata.annotations![MICROSOFT_GRAPH_USER_ID_ANNOTATION];\n\n retrieveItems(groupMemberOf, id).forEach(p => {\n const parentGroup = groupMap.get(p);\n if (parentGroup) {\n if (!user.spec.memberOf) {\n user.spec.memberOf = [];\n }\n user.spec.memberOf.push(stringifyEntityRef(parentGroup));\n }\n });\n });\n\n // Make sure all transitive memberships are available\n buildMemberOf(groups, users);\n}\n\n/**\n * Reads an entire org as Group and User entities.\n *\n * @public\n */\nexport async function readMicrosoftGraphOrg(\n client: MicrosoftGraphClient,\n tenantId: string,\n options: {\n userExpand?: string;\n userFilter?: string;\n userSelect?: string[];\n userPath?: string;\n loadUserPhotos?: boolean;\n userGroupMemberSearch?: string;\n userGroupMemberFilter?: string;\n userGroupMemberPath?: string;\n groupExpand?: string;\n groupSearch?: string;\n groupFilter?: string;\n groupSelect?: string[];\n groupPath?: string;\n groupIncludeSubGroups?: boolean;\n queryMode?: 'basic' | 'advanced';\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n logger: LoggerService;\n },\n): Promise<{ users: UserEntity[]; groups: GroupEntity[] }> {\n let users: UserEntity[] = [];\n\n if (\n options.userGroupMemberFilter ||\n options.userGroupMemberSearch ||\n options.userGroupMemberPath\n ) {\n const { users: usersInGroups } = await readMicrosoftGraphUsersInGroups(\n client,\n {\n queryMode: options.queryMode,\n userExpand: options.userExpand,\n userFilter: options.userFilter,\n userSelect: options.userSelect,\n userGroupMemberFilter: options.userGroupMemberFilter,\n userGroupMemberSearch: options.userGroupMemberSearch,\n userGroupMemberPath: options.userGroupMemberPath,\n loadUserPhotos: options.loadUserPhotos,\n transformer: options.userTransformer,\n logger: options.logger,\n },\n );\n users = usersInGroups;\n } else {\n const { users: usersWithFilter } = await readMicrosoftGraphUsers(client, {\n queryMode: options.queryMode,\n userExpand: options.userExpand,\n userFilter: options.userFilter,\n userSelect: options.userSelect,\n userPath: options.userPath,\n loadUserPhotos: options.loadUserPhotos,\n transformer: options.userTransformer,\n logger: options.logger,\n });\n users = usersWithFilter;\n }\n const { groups, rootGroup, groupMember, groupMemberOf } =\n await readMicrosoftGraphGroups(client, tenantId, {\n queryMode: options.queryMode,\n groupExpand: options.groupExpand,\n groupFilter: options.groupFilter,\n groupSearch: options.groupSearch,\n groupSelect: options.groupSelect,\n groupPath: options.groupPath,\n groupIncludeSubGroups: options.groupIncludeSubGroups,\n groupTransformer: options.groupTransformer,\n organizationTransformer: options.organizationTransformer,\n });\n\n resolveRelations(rootGroup, groups, users, groupMember, groupMemberOf);\n users.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n groups.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n\n return { users, groups };\n}\n\nasync function transformUsers(\n client: MicrosoftGraphClient,\n users: Iterable<MicrosoftGraph.User> | AsyncIterable<MicrosoftGraph.User>,\n logger: LoggerService,\n loadUserPhotos = true,\n transformer?: UserTransformer,\n) {\n const limiter = limiterFactory(10);\n\n const resolvedTransformer = transformer ?? defaultUserTransformer;\n const promises: Promise<void>[] = [];\n const entities: UserEntity[] = [];\n\n // Process all users in parallel, otherwise it can take quite some time\n for await (const user of users) {\n promises.push(\n limiter(async () => {\n let userPhoto;\n try {\n if (loadUserPhotos) {\n userPhoto = await client.getUserPhotoWithSizeLimit(\n user.id!,\n // We are limiting the photo size, as users with full resolution photos\n // can make the Backstage API slow\n 120,\n );\n }\n } catch (e) {\n logger.debug(`Unable to load user photo for`, {\n user: user.id,\n error: e,\n });\n }\n\n const entity = await resolvedTransformer(user, userPhoto);\n\n if (entity) {\n entities.push(entity);\n }\n }),\n );\n }\n\n // Wait for all users and photos to be downloaded\n await Promise.all(promises);\n\n logger.debug('Finished transforming users', {\n microsoftUserCount: promises.length,\n backstageUserCount: entities.length,\n });\n return entities;\n}\n\nfunction ensureItem(\n target: Map<string, Set<string>>,\n key: string,\n value: string,\n) {\n let set = target.get(key);\n if (!set) {\n set = new Set();\n target.set(key, set);\n }\n set!.add(value);\n}\n\nfunction retrieveItems(\n target: Map<string, Set<string>>,\n key: string,\n): Set<string> {\n return new Set([...(target.get(key) ?? [])].sort());\n}\n"],"names":["limiterFactory","defaultOrganizationTransformer","defaultGroupTransformer","MICROSOFT_GRAPH_GROUP_ID_ANNOTATION","MICROSOFT_GRAPH_TENANT_ID_ANNOTATION","stringifyEntityRef","buildOrgHierarchy","MICROSOFT_GRAPH_USER_ID_ANNOTATION","buildMemberOf","defaultUserTransformer"],"mappings":"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"}
1
+ {"version":3,"file":"read.cjs.js","sources":["../../src/microsoftGraph/read.ts"],"sourcesContent":["/*\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 GroupEntity,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport limiterFactory from 'p-limit';\nimport { MicrosoftGraphClient } from './client';\nimport {\n MICROSOFT_GRAPH_GROUP_ID_ANNOTATION,\n MICROSOFT_GRAPH_TENANT_ID_ANNOTATION,\n MICROSOFT_GRAPH_USER_ID_ANNOTATION,\n} from './constants';\nimport { buildMemberOf, buildOrgHierarchy } from './org';\nimport {\n GroupTransformer,\n OrganizationTransformer,\n UserTransformer,\n} from './types';\nimport {\n defaultGroupTransformer,\n defaultOrganizationTransformer,\n defaultUserTransformer,\n} from './defaultTransformers';\nimport * as MicrosoftGraph from '@microsoft/microsoft-graph-types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst PAGE_SIZE = 999;\n\nexport async function readMicrosoftGraphUsers(\n client: MicrosoftGraphClient,\n options: {\n queryMode?: 'basic' | 'advanced';\n userExpand?: string;\n userFilter?: string;\n userSelect?: string[];\n userPath?: string;\n loadUserPhotos?: boolean;\n transformer?: UserTransformer;\n logger: LoggerService;\n signal?: AbortSignal;\n },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n}> {\n const users = client.getUsers(\n {\n filter: options.userFilter,\n expand: options.userExpand,\n select: options.userSelect,\n top: PAGE_SIZE,\n },\n options.queryMode,\n options.userPath,\n options.signal,\n );\n\n return {\n users: await transformUsers(\n client,\n users,\n options.logger,\n options.loadUserPhotos,\n options.transformer,\n ),\n };\n}\n\nexport async function readMicrosoftGraphUsersInGroups(\n client: MicrosoftGraphClient,\n options: {\n queryMode?: 'basic' | 'advanced';\n userExpand?: string;\n userFilter?: string;\n userSelect?: string[];\n loadUserPhotos?: boolean;\n userGroupMemberSearch?: string;\n userGroupMemberFilter?: string;\n userGroupMemberPath?: string;\n groupExpand?: string;\n transformer?: UserTransformer;\n logger: LoggerService;\n signal?: AbortSignal;\n },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n}> {\n const limiter = limiterFactory(10);\n\n const userGroupMemberPromises: Promise<void>[] = [];\n const userGroupMembers = new Map<string, MicrosoftGraph.User>();\n\n for await (const group of client.getGroups(\n {\n expand: options.groupExpand,\n filter: options.userGroupMemberFilter,\n search: options.userGroupMemberSearch,\n select: ['id', 'displayName'],\n top: PAGE_SIZE,\n },\n options.queryMode,\n options.userGroupMemberPath,\n options.signal,\n )) {\n // Process all groups in parallel, otherwise it can take quite some time\n userGroupMemberPromises.push(\n limiter(async () => {\n let groupMemberCount = 0;\n for await (const user of client.getGroupUserMembers(\n group.id!,\n {\n expand: options.userExpand,\n filter: options.userFilter,\n select: options.userSelect,\n top: PAGE_SIZE,\n },\n options.queryMode,\n options.signal,\n )) {\n userGroupMembers.set(user.id!, user);\n groupMemberCount++;\n }\n options.logger.debug('Read users from group', {\n groupId: group.id,\n groupName: group.displayName,\n memberCount: groupMemberCount,\n });\n }),\n );\n }\n\n // Wait for all group members\n await Promise.all(userGroupMemberPromises);\n\n options.logger.info('Read users from group membership', {\n groupCount: userGroupMemberPromises.length,\n userCount: userGroupMembers.size,\n });\n\n return {\n users: await transformUsers(\n client,\n userGroupMembers.values(),\n options.logger,\n options.loadUserPhotos,\n options.transformer,\n ),\n };\n}\n\nexport async function readMicrosoftGraphOrganization(\n client: MicrosoftGraphClient,\n tenantId: string,\n options?: { transformer?: OrganizationTransformer; signal?: AbortSignal },\n): Promise<{\n rootGroup?: GroupEntity; // With all relations empty\n}> {\n // For now we expect a single root organization\n const organization = await client.getOrganization(tenantId, options?.signal);\n const transformer = options?.transformer ?? defaultOrganizationTransformer;\n const rootGroup = await transformer(organization);\n\n return { rootGroup };\n}\n\nexport async function readMicrosoftGraphGroups(\n client: MicrosoftGraphClient,\n tenantId: string,\n options?: {\n queryMode?: 'basic' | 'advanced';\n groupExpand?: string;\n groupFilter?: string;\n groupSearch?: string;\n groupSelect?: string[];\n groupPath?: string;\n groupIncludeSubGroups?: boolean;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n signal?: AbortSignal;\n },\n): Promise<{\n groups: GroupEntity[]; // With all relations empty\n rootGroup: GroupEntity | undefined; // With all relations empty\n groupMember: Map<string, Set<string>>;\n groupMemberOf: Map<string, Set<string>>;\n}> {\n const groups: GroupEntity[] = [];\n const groupMember: Map<string, Set<string>> = new Map();\n const groupMemberOf: Map<string, Set<string>> = new Map();\n const limiter = limiterFactory(10);\n\n const { rootGroup } = await readMicrosoftGraphOrganization(client, tenantId, {\n transformer: options?.organizationTransformer,\n signal: options?.signal,\n });\n if (rootGroup) {\n groupMember.set(rootGroup.metadata.name, new Set<string>());\n groups.push(rootGroup);\n }\n\n const transformer = options?.groupTransformer ?? defaultGroupTransformer;\n const promises: Promise<void>[] = [];\n\n for await (const group of client.getGroups(\n {\n expand: options?.groupExpand,\n filter: options?.groupFilter,\n search: options?.groupSearch,\n select: options?.groupSelect,\n top: PAGE_SIZE,\n },\n options?.queryMode,\n options?.groupPath,\n options?.signal,\n )) {\n // Process all groups in parallel, otherwise it can take quite some time\n promises.push(\n limiter(async () => {\n // TODO: Loading groups photos doesn't work right now as Microsoft Graph\n // doesn't allows this yet: https://microsoftgraph.uservoice.com/forums/920506-microsoft-graph-feature-requests/suggestions/37884922-allow-application-to-set-or-update-a-group-s-photo\n /* const groupPhoto = await client.getGroupPhotoWithSizeLimit(\n group.id!,\n // We are limiting the photo size, as groups with full resolution photos\n // can make the Backstage API slow\n 120,\n );*/\n\n const entity = await transformer(group /* , groupPhoto*/);\n\n if (!entity) {\n return;\n }\n\n for await (const member of client.getGroupMembers(\n group.id!,\n {\n top: PAGE_SIZE,\n },\n undefined,\n options?.signal,\n )) {\n if (!member.id) {\n continue;\n }\n\n if (member['@odata.type'] === '#microsoft.graph.user') {\n ensureItem(groupMemberOf, member.id, group.id!);\n }\n\n if (member['@odata.type'] === '#microsoft.graph.group') {\n ensureItem(groupMember, group.id!, member.id);\n\n if (options?.groupIncludeSubGroups) {\n const groupMemberEntity = await transformer(member);\n\n if (groupMemberEntity) {\n groups.push(groupMemberEntity);\n\n for await (const subMember of client.getGroupMembers(\n member.id!,\n { top: PAGE_SIZE },\n undefined,\n options?.signal,\n )) {\n if (!subMember.id) {\n continue;\n }\n\n if (subMember['@odata.type'] === '#microsoft.graph.user') {\n ensureItem(groupMemberOf, subMember.id, member.id!);\n }\n\n if (subMember['@odata.type'] === '#microsoft.graph.group') {\n ensureItem(groupMember, member.id!, subMember.id);\n }\n }\n }\n }\n }\n }\n\n groups.push(entity);\n }),\n );\n }\n\n // Wait for all group members and photos to be loaded\n await Promise.all(promises);\n\n return {\n groups,\n rootGroup,\n groupMember,\n groupMemberOf,\n };\n}\n\nexport function resolveRelations(\n rootGroup: GroupEntity | undefined,\n groups: GroupEntity[],\n users: UserEntity[],\n groupMember: Map<string, Set<string>>,\n groupMemberOf: Map<string, Set<string>>,\n) {\n // Build reference lookup tables, we reference them by the id of the graph\n const groupMap: Map<string, GroupEntity> = new Map(); // by group-id or tenant-id\n\n for (const group of groups) {\n if (group.metadata.annotations![MICROSOFT_GRAPH_GROUP_ID_ANNOTATION]) {\n groupMap.set(\n group.metadata.annotations![MICROSOFT_GRAPH_GROUP_ID_ANNOTATION],\n group,\n );\n }\n if (group.metadata.annotations![MICROSOFT_GRAPH_TENANT_ID_ANNOTATION]) {\n groupMap.set(\n group.metadata.annotations![MICROSOFT_GRAPH_TENANT_ID_ANNOTATION],\n group,\n );\n }\n }\n\n // Resolve all member relationships into the reverse direction\n const parentGroups = new Map<string, Set<string>>();\n\n groupMember.forEach((members, groupId) =>\n members.forEach(m => ensureItem(parentGroups, m, groupId)),\n );\n\n // Make sure every group (except root) has at least one parent. If the parent is missing, add the root.\n if (rootGroup) {\n const tenantId =\n rootGroup.metadata.annotations![MICROSOFT_GRAPH_TENANT_ID_ANNOTATION];\n\n groups.forEach(group => {\n const groupId =\n group.metadata.annotations![MICROSOFT_GRAPH_GROUP_ID_ANNOTATION];\n\n if (!groupId) {\n return;\n }\n\n if (retrieveItems(parentGroups, groupId).size === 0) {\n ensureItem(parentGroups, groupId, tenantId);\n ensureItem(groupMember, tenantId, groupId);\n }\n });\n }\n\n groups.forEach(group => {\n const id =\n group.metadata.annotations![MICROSOFT_GRAPH_GROUP_ID_ANNOTATION] ??\n group.metadata.annotations![MICROSOFT_GRAPH_TENANT_ID_ANNOTATION];\n\n retrieveItems(groupMember, id).forEach(m => {\n const childGroup = groupMap.get(m);\n if (childGroup) {\n group.spec.children.push(stringifyEntityRef(childGroup));\n }\n });\n\n // TODO: Until we have better support for multiple parents in the model,\n // the order of the parents is important as changing it causes\n // unnecessary entity stitching randomly.\n retrieveItems(parentGroups, id).forEach(p => {\n // Only set the parent if it doesn't exist yet\n if (group.spec.parent) {\n return;\n }\n const parentGroup = groupMap.get(p);\n if (parentGroup) {\n // TODO: Only having a single parent group might not match every companies model, but fine for now.\n group.spec.parent = stringifyEntityRef(parentGroup);\n }\n });\n });\n\n // Make sure that all groups have proper parents and children\n buildOrgHierarchy(groups);\n\n // Set relations for all users\n users.forEach(user => {\n const id = user.metadata.annotations![MICROSOFT_GRAPH_USER_ID_ANNOTATION];\n\n retrieveItems(groupMemberOf, id).forEach(p => {\n const parentGroup = groupMap.get(p);\n if (parentGroup) {\n if (!user.spec.memberOf) {\n user.spec.memberOf = [];\n }\n user.spec.memberOf.push(stringifyEntityRef(parentGroup));\n }\n });\n });\n\n // Make sure all transitive memberships are available\n buildMemberOf(groups, users);\n}\n\n/**\n * Reads an entire org as Group and User entities.\n *\n * @public\n */\nexport async function readMicrosoftGraphOrg(\n client: MicrosoftGraphClient,\n tenantId: string,\n options: {\n userExpand?: string;\n userFilter?: string;\n userSelect?: string[];\n userPath?: string;\n loadUserPhotos?: boolean;\n userGroupMemberSearch?: string;\n userGroupMemberFilter?: string;\n userGroupMemberPath?: string;\n groupExpand?: string;\n groupSearch?: string;\n groupFilter?: string;\n groupSelect?: string[];\n groupPath?: string;\n groupIncludeSubGroups?: boolean;\n queryMode?: 'basic' | 'advanced';\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n logger: LoggerService;\n signal?: AbortSignal;\n },\n): Promise<{ users: UserEntity[]; groups: GroupEntity[] }> {\n let users: UserEntity[] = [];\n\n if (\n options.userGroupMemberFilter ||\n options.userGroupMemberSearch ||\n options.userGroupMemberPath\n ) {\n const { users: usersInGroups } = await readMicrosoftGraphUsersInGroups(\n client,\n {\n queryMode: options.queryMode,\n userExpand: options.userExpand,\n userFilter: options.userFilter,\n userSelect: options.userSelect,\n userGroupMemberFilter: options.userGroupMemberFilter,\n userGroupMemberSearch: options.userGroupMemberSearch,\n userGroupMemberPath: options.userGroupMemberPath,\n loadUserPhotos: options.loadUserPhotos,\n transformer: options.userTransformer,\n logger: options.logger,\n signal: options.signal,\n },\n );\n users = usersInGroups;\n } else {\n const { users: usersWithFilter } = await readMicrosoftGraphUsers(client, {\n queryMode: options.queryMode,\n userExpand: options.userExpand,\n userFilter: options.userFilter,\n userSelect: options.userSelect,\n userPath: options.userPath,\n loadUserPhotos: options.loadUserPhotos,\n transformer: options.userTransformer,\n logger: options.logger,\n signal: options.signal,\n });\n users = usersWithFilter;\n }\n const { groups, rootGroup, groupMember, groupMemberOf } =\n await readMicrosoftGraphGroups(client, tenantId, {\n queryMode: options.queryMode,\n groupExpand: options.groupExpand,\n groupFilter: options.groupFilter,\n groupSearch: options.groupSearch,\n groupSelect: options.groupSelect,\n groupPath: options.groupPath,\n groupIncludeSubGroups: options.groupIncludeSubGroups,\n groupTransformer: options.groupTransformer,\n organizationTransformer: options.organizationTransformer,\n signal: options.signal,\n });\n\n resolveRelations(rootGroup, groups, users, groupMember, groupMemberOf);\n users.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n groups.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n\n return { users, groups };\n}\n\nasync function transformUsers(\n client: MicrosoftGraphClient,\n users: Iterable<MicrosoftGraph.User> | AsyncIterable<MicrosoftGraph.User>,\n logger: LoggerService,\n loadUserPhotos = true,\n transformer?: UserTransformer,\n) {\n const limiter = limiterFactory(10);\n\n const resolvedTransformer = transformer ?? defaultUserTransformer;\n const promises: Promise<void>[] = [];\n const entities: UserEntity[] = [];\n\n // Process all users in parallel, otherwise it can take quite some time\n for await (const user of users) {\n promises.push(\n limiter(async () => {\n let userPhoto;\n try {\n if (loadUserPhotos) {\n userPhoto = await client.getUserPhotoWithSizeLimit(\n user.id!,\n // We are limiting the photo size, as users with full resolution photos\n // can make the Backstage API slow\n 120,\n );\n }\n } catch (e) {\n logger.debug(`Unable to load user photo for`, {\n user: user.id,\n error: e,\n });\n }\n\n const entity = await resolvedTransformer(user, userPhoto);\n\n if (entity) {\n entities.push(entity);\n }\n }),\n );\n }\n\n // Wait for all users and photos to be downloaded\n await Promise.all(promises);\n\n logger.debug('Finished transforming users', {\n microsoftUserCount: promises.length,\n backstageUserCount: entities.length,\n });\n return entities;\n}\n\nfunction ensureItem(\n target: Map<string, Set<string>>,\n key: string,\n value: string,\n) {\n let set = target.get(key);\n if (!set) {\n set = new Set();\n target.set(key, set);\n }\n set!.add(value);\n}\n\nfunction retrieveItems(\n target: Map<string, Set<string>>,\n key: string,\n): Set<string> {\n return new Set([...(target.get(key) ?? [])].sort());\n}\n"],"names":["limiterFactory","defaultOrganizationTransformer","defaultGroupTransformer","MICROSOFT_GRAPH_GROUP_ID_ANNOTATION","MICROSOFT_GRAPH_TENANT_ID_ANNOTATION","stringifyEntityRef","buildOrgHierarchy","MICROSOFT_GRAPH_USER_ID_ANNOTATION","buildMemberOf","defaultUserTransformer"],"mappings":"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"}
@@ -161,7 +161,8 @@ class MicrosoftGraphOrgEntityProvider {
161
161
  groupTransformer: this.options.groupTransformer,
162
162
  userTransformer: this.options.userTransformer,
163
163
  organizationTransformer: this.options.organizationTransformer,
164
- logger
164
+ logger,
165
+ signal: options?.signal
165
166
  }
166
167
  );
167
168
  const { markCommitComplete } = markReadComplete({
@@ -183,15 +184,21 @@ class MicrosoftGraphOrgEntityProvider {
183
184
  const id = `${this.getProviderName()}:refresh`;
184
185
  await taskRunner.run({
185
186
  id,
186
- fn: async () => {
187
+ fn: async (abortSignal) => {
187
188
  const logger = this.options.logger.child({
188
189
  class: MicrosoftGraphOrgEntityProvider.prototype.constructor.name,
189
190
  taskId: id,
190
191
  taskInstanceId: uuid__namespace.v4()
191
192
  });
192
193
  try {
193
- await this.read({ logger });
194
+ await this.read({ logger, signal: abortSignal });
194
195
  } catch (error) {
196
+ if (error instanceof Error && error.name === "AbortError") {
197
+ logger.debug(
198
+ `${this.getProviderName()} refresh aborted due to shutdown`
199
+ );
200
+ return;
201
+ }
195
202
  logger.error(
196
203
  `${this.getProviderName()} refresh failed, ${error}`,
197
204
  error
@@ -1 +1 @@
1
- {"version":3,"file":"MicrosoftGraphOrgEntityProvider.cjs.js","sources":["../../src/processors/MicrosoftGraphOrgEntityProvider.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 {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n Entity,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n EntityProvider,\n EntityProviderConnection,\n} from '@backstage/plugin-catalog-node';\nimport { merge } from 'lodash';\nimport * as uuid from 'uuid';\nimport {\n GroupTransformer,\n MICROSOFT_GRAPH_GROUP_ID_ANNOTATION,\n MICROSOFT_GRAPH_TENANT_ID_ANNOTATION,\n MICROSOFT_GRAPH_USER_ID_ANNOTATION,\n MicrosoftGraphClient,\n MicrosoftGraphProviderConfig,\n ProviderConfigTransformer,\n OrganizationTransformer,\n readMicrosoftGraphConfig,\n readMicrosoftGraphOrg,\n UserTransformer,\n} from '../microsoftGraph';\nimport { readProviderConfigs } from '../microsoftGraph/config';\nimport {\n LoggerService,\n SchedulerService,\n SchedulerServiceTaskRunner,\n} from '@backstage/backend-plugin-api';\n\n/**\n * Options for {@link MicrosoftGraphOrgEntityProvider}.\n *\n * @public\n */\nexport type MicrosoftGraphOrgEntityProviderOptions =\n | MicrosoftGraphOrgEntityProviderLegacyOptions\n | {\n /**\n * The logger to use.\n */\n logger: LoggerService;\n\n /**\n * The refresh schedule to use.\n *\n * @remarks\n *\n * If you pass in 'manual', you are responsible for calling the `read` method\n * manually at some interval.\n *\n * But more commonly you will pass in the result of\n * {@link @backstage/backend-plugin-api#SchedulerService.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule?: 'manual' | SchedulerServiceTaskRunner;\n\n /**\n * Scheduler used to schedule refreshes based on\n * the schedule config.\n */\n scheduler?: SchedulerService;\n\n /**\n * The function that transforms a user entry in msgraph to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n userTransformer?: UserTransformer | Record<string, UserTransformer>;\n\n /**\n * The function that transforms a group entry in msgraph to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n groupTransformer?: GroupTransformer | Record<string, GroupTransformer>;\n\n /**\n * The function that transforms an organization entry in msgraph to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n organizationTransformer?:\n | OrganizationTransformer\n | Record<string, OrganizationTransformer>;\n\n /**\n * The function that transforms provider config dynamically.\n */\n providerConfigTransformer?:\n | ProviderConfigTransformer\n | Record<string, ProviderConfigTransformer>;\n };\n\n/**\n * Legacy options for {@link MicrosoftGraphOrgEntityProvider}\n * based on `catalog.processors.microsoftGraphOrg`.\n *\n * @public\n * @deprecated This interface exists for backwards compatibility only and will be removed in the future.\n */\nexport interface MicrosoftGraphOrgEntityProviderLegacyOptions {\n /**\n * A unique, stable identifier for this provider.\n *\n * @example \"production\"\n */\n id: string;\n\n /**\n * The target that this provider should consume.\n *\n * Should exactly match the \"target\" field of one of the provider\n * configuration entries.\n */\n target: string;\n\n /**\n * The logger to use.\n */\n logger: LoggerService;\n\n /**\n * The refresh schedule to use.\n *\n * @remarks\n *\n * If you pass in 'manual', you are responsible for calling the `read` method\n * manually at some interval.\n *\n * But more commonly you will pass in the result of\n * {@link @backstage/backend-plugin-api#SchedulerService.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule: 'manual' | SchedulerServiceTaskRunner;\n\n /**\n * The function that transforms a user entry in msgraph to an entity.\n */\n userTransformer?: UserTransformer;\n\n /**\n * The function that transforms a group entry in msgraph to an entity.\n */\n groupTransformer?: GroupTransformer;\n\n /**\n * The function that transforms an organization entry in msgraph to an entity.\n */\n organizationTransformer?: OrganizationTransformer;\n\n /**\n * The function that transforms provider config dynamically.\n */\n providerConfigTransformer?: ProviderConfigTransformer;\n}\n\n/**\n * Reads user and group entries out of Microsoft Graph, and provides them as\n * User and Group entities for the catalog.\n *\n * @public\n */\nexport class MicrosoftGraphOrgEntityProvider implements EntityProvider {\n private connection?: EntityProviderConnection;\n private scheduleFn?: () => Promise<void>;\n\n static fromConfig(\n configRoot: Config,\n options: MicrosoftGraphOrgEntityProviderOptions,\n ): MicrosoftGraphOrgEntityProvider[] {\n if ('id' in options) {\n return [\n MicrosoftGraphOrgEntityProvider.fromLegacyConfig(configRoot, options),\n ];\n }\n\n if (!options.schedule && !options.scheduler) {\n throw new Error('Either schedule or scheduler must be provided.');\n }\n\n function getTransformer<T extends Function>(\n id: string,\n transformers?: T | Record<string, T>,\n ): T | undefined {\n if (['undefined', 'function'].includes(typeof transformers)) {\n return transformers as T;\n }\n\n return (transformers as Record<string, T>)[id];\n }\n\n return readProviderConfigs(configRoot).map(providerConfig => {\n if (!options.schedule && !providerConfig.schedule) {\n throw new Error(\n `No schedule provided neither via code nor config for MicrosoftGraphOrgEntityProvider:${providerConfig.id}.`,\n );\n }\n\n const taskRunner =\n options.schedule ??\n options.scheduler!.createScheduledTaskRunner(providerConfig.schedule!);\n\n const provider = new MicrosoftGraphOrgEntityProvider({\n id: providerConfig.id,\n provider: providerConfig,\n logger: options.logger,\n userTransformer: getTransformer(\n providerConfig.id,\n options.userTransformer,\n ),\n groupTransformer: getTransformer(\n providerConfig.id,\n options.groupTransformer,\n ),\n organizationTransformer: getTransformer(\n providerConfig.id,\n options.organizationTransformer,\n ),\n providerConfigTransformer: getTransformer(\n providerConfig.id,\n options.providerConfigTransformer,\n ),\n });\n\n if (taskRunner !== 'manual') {\n provider.schedule(taskRunner);\n }\n\n return provider;\n });\n }\n\n /**\n * @deprecated Exists for backwards compatibility only and will be removed in the future.\n */\n private static fromLegacyConfig(\n configRoot: Config,\n options: MicrosoftGraphOrgEntityProviderLegacyOptions,\n ): MicrosoftGraphOrgEntityProvider {\n options.logger.warn(\n 'Deprecated msgraph config \"catalog.processors.microsoftGraphOrg\" used. Use \"catalog.providers.microsoftGraphOrg\" instead. More info at https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-msgraph/CHANGELOG.md#040-next1',\n );\n const config = configRoot.getOptionalConfig(\n 'catalog.processors.microsoftGraphOrg',\n );\n const providers = config ? readMicrosoftGraphConfig(config) : [];\n const provider = providers.find(p => options.target.startsWith(p.target));\n\n if (!provider) {\n throw new Error(\n `There is no Microsoft Graph Org provider that matches \"${options.target}\". Please add a configuration entry for it under \"catalog.processors.microsoftGraphOrg.providers\".`,\n );\n }\n\n const logger = options.logger.child({\n target: options.target,\n });\n\n const result = new MicrosoftGraphOrgEntityProvider({\n id: options.id,\n userTransformer: options.userTransformer,\n groupTransformer: options.groupTransformer,\n organizationTransformer: options.organizationTransformer,\n providerConfigTransformer: options.providerConfigTransformer,\n logger,\n provider,\n });\n\n if (options.schedule !== 'manual') {\n result.schedule(options.schedule);\n }\n\n return result;\n }\n\n private options: {\n id: string;\n provider: MicrosoftGraphProviderConfig;\n logger: LoggerService;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n providerConfigTransformer?: ProviderConfigTransformer;\n };\n\n constructor(options: {\n id: string;\n provider: MicrosoftGraphProviderConfig;\n logger: LoggerService;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n providerConfigTransformer?: ProviderConfigTransformer;\n }) {\n this.options = options;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-node#EntityProvider.getProviderName} */\n getProviderName() {\n return `MicrosoftGraphOrgEntityProvider:${this.options.id}`;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-node#EntityProvider.connect} */\n async connect(connection: EntityProviderConnection) {\n this.connection = connection;\n await this.scheduleFn?.();\n }\n\n /**\n * Runs one complete ingestion loop. Call this method regularly at some\n * appropriate cadence.\n */\n async read(options?: { logger?: LoggerService }) {\n if (!this.connection) {\n throw new Error('Not initialized');\n }\n\n const logger = options?.logger ?? this.options.logger;\n const provider = this.options.providerConfigTransformer\n ? await this.options.providerConfigTransformer(this.options.provider)\n : this.options.provider;\n const { markReadComplete } = trackProgress(logger);\n const client = MicrosoftGraphClient.create(this.options.provider);\n\n const { users, groups } = await readMicrosoftGraphOrg(\n client,\n provider.tenantId,\n {\n userExpand: provider.userExpand,\n userFilter: provider.userFilter,\n userSelect: provider.userSelect,\n userPath: provider.userPath,\n loadUserPhotos: provider.loadUserPhotos,\n userGroupMemberFilter: provider.userGroupMemberFilter,\n userGroupMemberSearch: provider.userGroupMemberSearch,\n userGroupMemberPath: provider.userGroupMemberPath,\n groupExpand: provider.groupExpand,\n groupFilter: provider.groupFilter,\n groupSearch: provider.groupSearch,\n groupSelect: provider.groupSelect,\n groupPath: provider.groupPath,\n groupIncludeSubGroups: provider.groupIncludeSubGroups,\n queryMode: provider.queryMode,\n groupTransformer: this.options.groupTransformer,\n userTransformer: this.options.userTransformer,\n organizationTransformer: this.options.organizationTransformer,\n logger: logger,\n },\n );\n\n const { markCommitComplete } = markReadComplete({\n users,\n groups,\n tenantId: provider.tenantId,\n });\n\n await this.connection.applyMutation({\n type: 'full',\n entities: [...users, ...groups].map(entity => ({\n locationKey: `msgraph-org-provider:${this.options.id}`,\n entity: withLocations(this.options.id, entity),\n })),\n });\n\n markCommitComplete(groups.length, users.length, provider.tenantId);\n }\n\n private schedule(taskRunner: SchedulerServiceTaskRunner) {\n this.scheduleFn = async () => {\n const id = `${this.getProviderName()}:refresh`;\n await taskRunner.run({\n id,\n fn: async () => {\n const logger = this.options.logger.child({\n class: MicrosoftGraphOrgEntityProvider.prototype.constructor.name,\n taskId: id,\n taskInstanceId: uuid.v4(),\n });\n\n try {\n await this.read({ logger });\n } catch (error) {\n logger.error(\n `${this.getProviderName()} refresh failed, ${error}`,\n error,\n );\n }\n },\n });\n };\n }\n}\n\n// Helps wrap the timing and logging behaviors\nfunction trackProgress(logger: LoggerService) {\n let timestamp = Date.now();\n let summary: string;\n\n logger.info('Reading msgraph users and groups');\n\n function markReadComplete(read: {\n users: unknown[];\n groups: unknown[];\n tenantId: string;\n }) {\n summary = `${read.users.length} msgraph users and ${read.groups.length} msgraph groups`;\n const readDuration = ((Date.now() - timestamp) / 1000).toFixed(1);\n timestamp = Date.now();\n logger.info(`Read ${summary} in ${readDuration} seconds. Committing...`, {\n readDuration,\n tenantId: read.tenantId,\n usersCount: read.users.length,\n groupsCount: read.groups.length,\n });\n return { markCommitComplete };\n }\n\n function markCommitComplete(\n groupsCount: number,\n usersCount: number,\n tenantId: string,\n ) {\n const commitDuration = ((Date.now() - timestamp) / 1000).toFixed(1);\n logger.info(`Committed ${summary} in ${commitDuration} seconds.`, {\n commitDuration,\n tenantId,\n usersCount,\n groupsCount,\n });\n }\n\n return { markReadComplete };\n}\n\n// Makes sure that emitted entities have a proper location based on their uuid\nexport function withLocations(providerId: string, entity: Entity): Entity {\n const uid =\n entity.metadata.annotations?.[MICROSOFT_GRAPH_USER_ID_ANNOTATION] ||\n entity.metadata.annotations?.[MICROSOFT_GRAPH_GROUP_ID_ANNOTATION] ||\n entity.metadata.annotations?.[MICROSOFT_GRAPH_TENANT_ID_ANNOTATION] ||\n entity.metadata.name;\n const location = `msgraph:${providerId}/${encodeURIComponent(uid)}`;\n return merge(\n {\n metadata: {\n annotations: {\n [ANNOTATION_LOCATION]: location,\n [ANNOTATION_ORIGIN_LOCATION]: location,\n },\n },\n },\n entity,\n ) as Entity;\n}\n"],"names":["readProviderConfigs","config","readMicrosoftGraphConfig","client","MicrosoftGraphClient","readMicrosoftGraphOrg","uuid","MICROSOFT_GRAPH_USER_ID_ANNOTATION","MICROSOFT_GRAPH_GROUP_ID_ANNOTATION","MICROSOFT_GRAPH_TENANT_ID_ANNOTATION","merge","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION"],"mappings":"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"}
1
+ {"version":3,"file":"MicrosoftGraphOrgEntityProvider.cjs.js","sources":["../../src/processors/MicrosoftGraphOrgEntityProvider.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 {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n Entity,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n EntityProvider,\n EntityProviderConnection,\n} from '@backstage/plugin-catalog-node';\nimport { merge } from 'lodash';\nimport * as uuid from 'uuid';\nimport {\n GroupTransformer,\n MICROSOFT_GRAPH_GROUP_ID_ANNOTATION,\n MICROSOFT_GRAPH_TENANT_ID_ANNOTATION,\n MICROSOFT_GRAPH_USER_ID_ANNOTATION,\n MicrosoftGraphClient,\n MicrosoftGraphProviderConfig,\n ProviderConfigTransformer,\n OrganizationTransformer,\n readMicrosoftGraphConfig,\n readMicrosoftGraphOrg,\n UserTransformer,\n} from '../microsoftGraph';\nimport { readProviderConfigs } from '../microsoftGraph/config';\nimport {\n LoggerService,\n SchedulerService,\n SchedulerServiceTaskRunner,\n} from '@backstage/backend-plugin-api';\n\n/**\n * Options for {@link MicrosoftGraphOrgEntityProvider}.\n *\n * @public\n */\nexport type MicrosoftGraphOrgEntityProviderOptions =\n | MicrosoftGraphOrgEntityProviderLegacyOptions\n | {\n /**\n * The logger to use.\n */\n logger: LoggerService;\n\n /**\n * The refresh schedule to use.\n *\n * @remarks\n *\n * If you pass in 'manual', you are responsible for calling the `read` method\n * manually at some interval.\n *\n * But more commonly you will pass in the result of\n * {@link @backstage/backend-plugin-api#SchedulerService.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule?: 'manual' | SchedulerServiceTaskRunner;\n\n /**\n * Scheduler used to schedule refreshes based on\n * the schedule config.\n */\n scheduler?: SchedulerService;\n\n /**\n * The function that transforms a user entry in msgraph to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n userTransformer?: UserTransformer | Record<string, UserTransformer>;\n\n /**\n * The function that transforms a group entry in msgraph to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n groupTransformer?: GroupTransformer | Record<string, GroupTransformer>;\n\n /**\n * The function that transforms an organization entry in msgraph to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n organizationTransformer?:\n | OrganizationTransformer\n | Record<string, OrganizationTransformer>;\n\n /**\n * The function that transforms provider config dynamically.\n */\n providerConfigTransformer?:\n | ProviderConfigTransformer\n | Record<string, ProviderConfigTransformer>;\n };\n\n/**\n * Legacy options for {@link MicrosoftGraphOrgEntityProvider}\n * based on `catalog.processors.microsoftGraphOrg`.\n *\n * @public\n * @deprecated This interface exists for backwards compatibility only and will be removed in the future.\n */\nexport interface MicrosoftGraphOrgEntityProviderLegacyOptions {\n /**\n * A unique, stable identifier for this provider.\n *\n * @example \"production\"\n */\n id: string;\n\n /**\n * The target that this provider should consume.\n *\n * Should exactly match the \"target\" field of one of the provider\n * configuration entries.\n */\n target: string;\n\n /**\n * The logger to use.\n */\n logger: LoggerService;\n\n /**\n * The refresh schedule to use.\n *\n * @remarks\n *\n * If you pass in 'manual', you are responsible for calling the `read` method\n * manually at some interval.\n *\n * But more commonly you will pass in the result of\n * {@link @backstage/backend-plugin-api#SchedulerService.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule: 'manual' | SchedulerServiceTaskRunner;\n\n /**\n * The function that transforms a user entry in msgraph to an entity.\n */\n userTransformer?: UserTransformer;\n\n /**\n * The function that transforms a group entry in msgraph to an entity.\n */\n groupTransformer?: GroupTransformer;\n\n /**\n * The function that transforms an organization entry in msgraph to an entity.\n */\n organizationTransformer?: OrganizationTransformer;\n\n /**\n * The function that transforms provider config dynamically.\n */\n providerConfigTransformer?: ProviderConfigTransformer;\n}\n\n/**\n * Reads user and group entries out of Microsoft Graph, and provides them as\n * User and Group entities for the catalog.\n *\n * @public\n */\nexport class MicrosoftGraphOrgEntityProvider implements EntityProvider {\n private connection?: EntityProviderConnection;\n private scheduleFn?: () => Promise<void>;\n\n static fromConfig(\n configRoot: Config,\n options: MicrosoftGraphOrgEntityProviderOptions,\n ): MicrosoftGraphOrgEntityProvider[] {\n if ('id' in options) {\n return [\n MicrosoftGraphOrgEntityProvider.fromLegacyConfig(configRoot, options),\n ];\n }\n\n if (!options.schedule && !options.scheduler) {\n throw new Error('Either schedule or scheduler must be provided.');\n }\n\n function getTransformer<T extends Function>(\n id: string,\n transformers?: T | Record<string, T>,\n ): T | undefined {\n if (['undefined', 'function'].includes(typeof transformers)) {\n return transformers as T;\n }\n\n return (transformers as Record<string, T>)[id];\n }\n\n return readProviderConfigs(configRoot).map(providerConfig => {\n if (!options.schedule && !providerConfig.schedule) {\n throw new Error(\n `No schedule provided neither via code nor config for MicrosoftGraphOrgEntityProvider:${providerConfig.id}.`,\n );\n }\n\n const taskRunner =\n options.schedule ??\n options.scheduler!.createScheduledTaskRunner(providerConfig.schedule!);\n\n const provider = new MicrosoftGraphOrgEntityProvider({\n id: providerConfig.id,\n provider: providerConfig,\n logger: options.logger,\n userTransformer: getTransformer(\n providerConfig.id,\n options.userTransformer,\n ),\n groupTransformer: getTransformer(\n providerConfig.id,\n options.groupTransformer,\n ),\n organizationTransformer: getTransformer(\n providerConfig.id,\n options.organizationTransformer,\n ),\n providerConfigTransformer: getTransformer(\n providerConfig.id,\n options.providerConfigTransformer,\n ),\n });\n\n if (taskRunner !== 'manual') {\n provider.schedule(taskRunner);\n }\n\n return provider;\n });\n }\n\n /**\n * @deprecated Exists for backwards compatibility only and will be removed in the future.\n */\n private static fromLegacyConfig(\n configRoot: Config,\n options: MicrosoftGraphOrgEntityProviderLegacyOptions,\n ): MicrosoftGraphOrgEntityProvider {\n options.logger.warn(\n 'Deprecated msgraph config \"catalog.processors.microsoftGraphOrg\" used. Use \"catalog.providers.microsoftGraphOrg\" instead. More info at https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-msgraph/CHANGELOG.md#040-next1',\n );\n const config = configRoot.getOptionalConfig(\n 'catalog.processors.microsoftGraphOrg',\n );\n const providers = config ? readMicrosoftGraphConfig(config) : [];\n const provider = providers.find(p => options.target.startsWith(p.target));\n\n if (!provider) {\n throw new Error(\n `There is no Microsoft Graph Org provider that matches \"${options.target}\". Please add a configuration entry for it under \"catalog.processors.microsoftGraphOrg.providers\".`,\n );\n }\n\n const logger = options.logger.child({\n target: options.target,\n });\n\n const result = new MicrosoftGraphOrgEntityProvider({\n id: options.id,\n userTransformer: options.userTransformer,\n groupTransformer: options.groupTransformer,\n organizationTransformer: options.organizationTransformer,\n providerConfigTransformer: options.providerConfigTransformer,\n logger,\n provider,\n });\n\n if (options.schedule !== 'manual') {\n result.schedule(options.schedule);\n }\n\n return result;\n }\n\n private options: {\n id: string;\n provider: MicrosoftGraphProviderConfig;\n logger: LoggerService;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n providerConfigTransformer?: ProviderConfigTransformer;\n };\n\n constructor(options: {\n id: string;\n provider: MicrosoftGraphProviderConfig;\n logger: LoggerService;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n providerConfigTransformer?: ProviderConfigTransformer;\n }) {\n this.options = options;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-node#EntityProvider.getProviderName} */\n getProviderName() {\n return `MicrosoftGraphOrgEntityProvider:${this.options.id}`;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-node#EntityProvider.connect} */\n async connect(connection: EntityProviderConnection) {\n this.connection = connection;\n await this.scheduleFn?.();\n }\n\n /**\n * Runs one complete ingestion loop. Call this method regularly at some\n * appropriate cadence.\n */\n async read(options?: { logger?: LoggerService; signal?: AbortSignal }) {\n if (!this.connection) {\n throw new Error('Not initialized');\n }\n\n const logger = options?.logger ?? this.options.logger;\n const provider = this.options.providerConfigTransformer\n ? await this.options.providerConfigTransformer(this.options.provider)\n : this.options.provider;\n const { markReadComplete } = trackProgress(logger);\n const client = MicrosoftGraphClient.create(this.options.provider);\n\n const { users, groups } = await readMicrosoftGraphOrg(\n client,\n provider.tenantId,\n {\n userExpand: provider.userExpand,\n userFilter: provider.userFilter,\n userSelect: provider.userSelect,\n userPath: provider.userPath,\n loadUserPhotos: provider.loadUserPhotos,\n userGroupMemberFilter: provider.userGroupMemberFilter,\n userGroupMemberSearch: provider.userGroupMemberSearch,\n userGroupMemberPath: provider.userGroupMemberPath,\n groupExpand: provider.groupExpand,\n groupFilter: provider.groupFilter,\n groupSearch: provider.groupSearch,\n groupSelect: provider.groupSelect,\n groupPath: provider.groupPath,\n groupIncludeSubGroups: provider.groupIncludeSubGroups,\n queryMode: provider.queryMode,\n groupTransformer: this.options.groupTransformer,\n userTransformer: this.options.userTransformer,\n organizationTransformer: this.options.organizationTransformer,\n logger: logger,\n signal: options?.signal,\n },\n );\n\n const { markCommitComplete } = markReadComplete({\n users,\n groups,\n tenantId: provider.tenantId,\n });\n\n await this.connection.applyMutation({\n type: 'full',\n entities: [...users, ...groups].map(entity => ({\n locationKey: `msgraph-org-provider:${this.options.id}`,\n entity: withLocations(this.options.id, entity),\n })),\n });\n\n markCommitComplete(groups.length, users.length, provider.tenantId);\n }\n\n private schedule(taskRunner: SchedulerServiceTaskRunner) {\n this.scheduleFn = async () => {\n const id = `${this.getProviderName()}:refresh`;\n await taskRunner.run({\n id,\n fn: async (abortSignal: AbortSignal) => {\n const logger = this.options.logger.child({\n class: MicrosoftGraphOrgEntityProvider.prototype.constructor.name,\n taskId: id,\n taskInstanceId: uuid.v4(),\n });\n\n try {\n await this.read({ logger, signal: abortSignal });\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n logger.debug(\n `${this.getProviderName()} refresh aborted due to shutdown`,\n );\n return;\n }\n logger.error(\n `${this.getProviderName()} refresh failed, ${error}`,\n error,\n );\n }\n },\n });\n };\n }\n}\n\n// Helps wrap the timing and logging behaviors\nfunction trackProgress(logger: LoggerService) {\n let timestamp = Date.now();\n let summary: string;\n\n logger.info('Reading msgraph users and groups');\n\n function markReadComplete(read: {\n users: unknown[];\n groups: unknown[];\n tenantId: string;\n }) {\n summary = `${read.users.length} msgraph users and ${read.groups.length} msgraph groups`;\n const readDuration = ((Date.now() - timestamp) / 1000).toFixed(1);\n timestamp = Date.now();\n logger.info(`Read ${summary} in ${readDuration} seconds. Committing...`, {\n readDuration,\n tenantId: read.tenantId,\n usersCount: read.users.length,\n groupsCount: read.groups.length,\n });\n return { markCommitComplete };\n }\n\n function markCommitComplete(\n groupsCount: number,\n usersCount: number,\n tenantId: string,\n ) {\n const commitDuration = ((Date.now() - timestamp) / 1000).toFixed(1);\n logger.info(`Committed ${summary} in ${commitDuration} seconds.`, {\n commitDuration,\n tenantId,\n usersCount,\n groupsCount,\n });\n }\n\n return { markReadComplete };\n}\n\n// Makes sure that emitted entities have a proper location based on their uuid\nexport function withLocations(providerId: string, entity: Entity): Entity {\n const uid =\n entity.metadata.annotations?.[MICROSOFT_GRAPH_USER_ID_ANNOTATION] ||\n entity.metadata.annotations?.[MICROSOFT_GRAPH_GROUP_ID_ANNOTATION] ||\n entity.metadata.annotations?.[MICROSOFT_GRAPH_TENANT_ID_ANNOTATION] ||\n entity.metadata.name;\n const location = `msgraph:${providerId}/${encodeURIComponent(uid)}`;\n return merge(\n {\n metadata: {\n annotations: {\n [ANNOTATION_LOCATION]: location,\n [ANNOTATION_ORIGIN_LOCATION]: location,\n },\n },\n },\n entity,\n ) as Entity;\n}\n"],"names":["readProviderConfigs","config","readMicrosoftGraphConfig","client","MicrosoftGraphClient","readMicrosoftGraphOrg","uuid","MICROSOFT_GRAPH_USER_ID_ANNOTATION","MICROSOFT_GRAPH_GROUP_ID_ANNOTATION","MICROSOFT_GRAPH_TENANT_ID_ANNOTATION","merge","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend-module-msgraph",
3
- "version": "0.9.1-next.0",
3
+ "version": "0.9.1-next.1",
4
4
  "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph",
5
5
  "backstage": {
6
6
  "role": "backend-plugin-module",
@@ -66,11 +66,11 @@
66
66
  },
67
67
  "dependencies": {
68
68
  "@azure/identity": "^4.0.0",
69
- "@backstage/backend-plugin-api": "1.7.1-next.0",
69
+ "@backstage/backend-plugin-api": "1.8.0-next.1",
70
70
  "@backstage/catalog-model": "1.7.6",
71
71
  "@backstage/config": "1.3.6",
72
72
  "@backstage/plugin-catalog-common": "1.1.8",
73
- "@backstage/plugin-catalog-node": "2.1.0-next.0",
73
+ "@backstage/plugin-catalog-node": "2.1.0-next.2",
74
74
  "@microsoft/microsoft-graph-types": "^2.6.0",
75
75
  "lodash": "^4.17.21",
76
76
  "p-limit": "^3.0.2",
@@ -78,8 +78,8 @@
78
78
  "uuid": "^11.0.0"
79
79
  },
80
80
  "devDependencies": {
81
- "@backstage/backend-test-utils": "1.11.1-next.0",
82
- "@backstage/cli": "0.35.5-next.0",
81
+ "@backstage/backend-test-utils": "1.11.1-next.2",
82
+ "@backstage/cli": "0.36.0-next.2",
83
83
  "@types/lodash": "^4.14.151",
84
84
  "msw": "^1.0.0"
85
85
  },