@backstage/plugin-catalog-backend-module-msgraph 0.4.0 → 0.4.1-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @backstage/plugin-catalog-backend-module-msgraph
2
2
 
3
+ ## 0.4.1-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - b1995df9f3: Adjust references in deprecation warnings to point to stable URL/document.
8
+ - Updated dependencies
9
+ - @backstage/backend-tasks@0.3.4-next.0
10
+ - @backstage/plugin-catalog-backend@1.3.1-next.0
11
+
3
12
  ## 0.4.0
4
13
 
5
14
  ### Minor Changes
package/dist/index.cjs.js CHANGED
@@ -46,7 +46,12 @@ class MicrosoftGraphClient {
46
46
  authorityHost: config.authority,
47
47
  tenantId: config.tenantId
48
48
  };
49
- const credential = config.clientId && config.clientSecret ? new identity.ClientSecretCredential(config.tenantId, config.clientId, config.clientSecret, options) : new identity.DefaultAzureCredential(options);
49
+ const credential = config.clientId && config.clientSecret ? new identity.ClientSecretCredential(
50
+ config.tenantId,
51
+ config.clientId,
52
+ config.clientSecret,
53
+ options
54
+ ) : new identity.DefaultAzureCredential(options);
50
55
  return new MicrosoftGraphClient(config.target, credential);
51
56
  }
52
57
  async *requestCollection(path, query, queryMode) {
@@ -73,20 +78,28 @@ class MicrosoftGraphClient {
73
78
  }
74
79
  async requestApi(path, query, headers) {
75
80
  var _a;
76
- const queryString = qs__default["default"].stringify({
77
- $search: query == null ? void 0 : query.search,
78
- $filter: query == null ? void 0 : query.filter,
79
- $select: (_a = query == null ? void 0 : query.select) == null ? void 0 : _a.join(","),
80
- $expand: query == null ? void 0 : query.expand,
81
- $count: query == null ? void 0 : query.count
82
- }, {
83
- addQueryPrefix: true,
84
- encode: false
85
- });
86
- return await this.requestRaw(`${this.baseUrl}/${path}${queryString}`, headers);
81
+ const queryString = qs__default["default"].stringify(
82
+ {
83
+ $search: query == null ? void 0 : query.search,
84
+ $filter: query == null ? void 0 : query.filter,
85
+ $select: (_a = query == null ? void 0 : query.select) == null ? void 0 : _a.join(","),
86
+ $expand: query == null ? void 0 : query.expand,
87
+ $count: query == null ? void 0 : query.count
88
+ },
89
+ {
90
+ addQueryPrefix: true,
91
+ encode: false
92
+ }
93
+ );
94
+ return await this.requestRaw(
95
+ `${this.baseUrl}/${path}${queryString}`,
96
+ headers
97
+ );
87
98
  }
88
99
  async requestRaw(url, headers) {
89
- const token = await this.tokenCredential.getToken("https://graph.microsoft.com/.default");
100
+ const token = await this.tokenCredential.getToken(
101
+ "https://graph.microsoft.com/.default"
102
+ );
90
103
  if (!token) {
91
104
  throw new Error("Failed to obtain token from Azure Identity");
92
105
  }
@@ -111,7 +124,11 @@ class MicrosoftGraphClient {
111
124
  return await this.getPhoto("users", userId, sizeId);
112
125
  }
113
126
  async *getUsers(query, queryMode) {
114
- yield* this.requestCollection(`users`, query, queryMode);
127
+ yield* this.requestCollection(
128
+ `users`,
129
+ query,
130
+ queryMode
131
+ );
115
132
  }
116
133
  async getGroupPhotoWithSizeLimit(groupId, maxSize) {
117
134
  return await this.getPhotoWithSizeLimit("groups", groupId, maxSize);
@@ -120,7 +137,11 @@ class MicrosoftGraphClient {
120
137
  return await this.getPhoto("groups", groupId, sizeId);
121
138
  }
122
139
  async *getGroups(query, queryMode) {
123
- yield* this.requestCollection(`groups`, query, queryMode);
140
+ yield* this.requestCollection(
141
+ `groups`,
142
+ query,
143
+ queryMode
144
+ );
124
145
  }
125
146
  async *getGroupMembers(groupId) {
126
147
  yield* this.requestCollection(`groups/${groupId}/members`);
@@ -160,12 +181,16 @@ class MicrosoftGraphClient {
160
181
  } else if (response.status !== 200) {
161
182
  await this.handleError("photo", response);
162
183
  }
163
- return `data:image/jpeg;base64,${Buffer.from(await response.arrayBuffer()).toString("base64")}`;
184
+ return `data:image/jpeg;base64,${Buffer.from(
185
+ await response.arrayBuffer()
186
+ ).toString("base64")}`;
164
187
  }
165
188
  async handleError(path, response) {
166
189
  const result = await response.json();
167
190
  const error = result.error;
168
- throw new Error(`Error while reading ${path} from Microsoft Graph: ${error.code} - ${error.message}`);
191
+ throw new Error(
192
+ `Error while reading ${path} from Microsoft Graph: ${error.code} - ${error.message}`
193
+ );
169
194
  }
170
195
  }
171
196
 
@@ -176,23 +201,34 @@ function readMicrosoftGraphConfig(config) {
176
201
  const providers = [];
177
202
  const providerConfigs = (_a = config.getOptionalConfigArray("providers")) != null ? _a : [];
178
203
  for (const providerConfig of providerConfigs) {
179
- const target = lodash.trimEnd((_b = providerConfig.getOptionalString("target")) != null ? _b : DEFAULT_TARGET, "/");
204
+ const target = lodash.trimEnd(
205
+ (_b = providerConfig.getOptionalString("target")) != null ? _b : DEFAULT_TARGET,
206
+ "/"
207
+ );
180
208
  const authority = providerConfig.getOptionalString("authority");
181
209
  const tenantId = providerConfig.getString("tenantId");
182
210
  const clientId = providerConfig.getOptionalString("clientId");
183
211
  const clientSecret = providerConfig.getOptionalString("clientSecret");
184
212
  const userExpand = providerConfig.getOptionalString("userExpand");
185
213
  const userFilter = providerConfig.getOptionalString("userFilter");
186
- const userGroupMemberFilter = providerConfig.getOptionalString("userGroupMemberFilter");
187
- const userGroupMemberSearch = providerConfig.getOptionalString("userGroupMemberSearch");
214
+ const userGroupMemberFilter = providerConfig.getOptionalString(
215
+ "userGroupMemberFilter"
216
+ );
217
+ const userGroupMemberSearch = providerConfig.getOptionalString(
218
+ "userGroupMemberSearch"
219
+ );
188
220
  const groupExpand = providerConfig.getOptionalString("groupExpand");
189
221
  const groupFilter = providerConfig.getOptionalString("groupFilter");
190
222
  const groupSearch = providerConfig.getOptionalString("groupSearch");
191
223
  if (userFilter && userGroupMemberFilter) {
192
- throw new Error(`userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.`);
224
+ throw new Error(
225
+ `userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.`
226
+ );
193
227
  }
194
228
  if (userFilter && userGroupMemberSearch) {
195
- throw new Error(`userGroupMemberSearch cannot be specified when userFilter is defined.`);
229
+ throw new Error(
230
+ `userGroupMemberSearch cannot be specified when userFilter is defined.`
231
+ );
196
232
  }
197
233
  const groupSelect = providerConfig.getOptionalStringArray("groupSelect");
198
234
  const queryMode = providerConfig.getOptionalString("queryMode");
@@ -200,10 +236,14 @@ function readMicrosoftGraphConfig(config) {
200
236
  throw new Error(`queryMode must be one of: basic, advanced`);
201
237
  }
202
238
  if (clientId && !clientSecret) {
203
- throw new Error(`clientSecret must be provided when clientId is defined.`);
239
+ throw new Error(
240
+ `clientSecret must be provided when clientId is defined.`
241
+ );
204
242
  }
205
243
  if (clientSecret && !clientId) {
206
- throw new Error(`clientId must be provided when clientSecret is defined.`);
244
+ throw new Error(
245
+ `clientId must be provided when clientSecret is defined.`
246
+ );
207
247
  }
208
248
  providers.push({
209
249
  id: target,
@@ -226,7 +266,9 @@ function readMicrosoftGraphConfig(config) {
226
266
  return providers;
227
267
  }
228
268
  function readProviderConfigs(config) {
229
- const providersConfig = config.getOptionalConfig("catalog.providers.microsoftGraphOrg");
269
+ const providersConfig = config.getOptionalConfig(
270
+ "catalog.providers.microsoftGraphOrg"
271
+ );
230
272
  if (!providersConfig) {
231
273
  return [];
232
274
  }
@@ -240,7 +282,10 @@ function readProviderConfigs(config) {
240
282
  }
241
283
  function readProviderConfig(id, config) {
242
284
  var _a;
243
- const target = lodash.trimEnd((_a = config.getOptionalString("target")) != null ? _a : DEFAULT_TARGET, "/");
285
+ const target = lodash.trimEnd(
286
+ (_a = config.getOptionalString("target")) != null ? _a : DEFAULT_TARGET,
287
+ "/"
288
+ );
244
289
  const authority = config.getOptionalString("authority");
245
290
  const tenantId = config.getString("tenantId");
246
291
  const clientId = config.getOptionalString("clientId");
@@ -251,13 +296,21 @@ function readProviderConfig(id, config) {
251
296
  const groupFilter = config.getOptionalString("group.filter");
252
297
  const groupSearch = config.getOptionalString("group.search");
253
298
  const groupSelect = config.getOptionalStringArray("group.select");
254
- const userGroupMemberFilter = config.getOptionalString("userGroupMember.filter");
255
- const userGroupMemberSearch = config.getOptionalString("userGroupMember.search");
299
+ const userGroupMemberFilter = config.getOptionalString(
300
+ "userGroupMember.filter"
301
+ );
302
+ const userGroupMemberSearch = config.getOptionalString(
303
+ "userGroupMember.search"
304
+ );
256
305
  if (userFilter && userGroupMemberFilter) {
257
- throw new Error(`userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.`);
306
+ throw new Error(
307
+ `userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.`
308
+ );
258
309
  }
259
310
  if (userFilter && userGroupMemberSearch) {
260
- throw new Error(`userGroupMemberSearch cannot be specified when userFilter is defined.`);
311
+ throw new Error(
312
+ `userGroupMemberSearch cannot be specified when userFilter is defined.`
313
+ );
261
314
  }
262
315
  if (clientId && !clientSecret) {
263
316
  throw new Error(`clientSecret must be provided when clientId is defined.`);
@@ -384,23 +437,31 @@ async function readMicrosoftGraphUsers(client, options) {
384
437
  const limiter = limiterFactory__default["default"](10);
385
438
  const transformer = (_a = options.transformer) != null ? _a : defaultUserTransformer;
386
439
  const promises = [];
387
- for await (const user of client.getUsers({
388
- filter: options.userFilter,
389
- expand: options.userExpand
390
- }, options.queryMode)) {
391
- promises.push(limiter(async () => {
392
- let userPhoto;
393
- try {
394
- userPhoto = await client.getUserPhotoWithSizeLimit(user.id, 120);
395
- } catch (e) {
396
- options.logger.warn(`Unable to load photo for ${user.id}`);
397
- }
398
- const entity = await transformer(user, userPhoto);
399
- if (!entity) {
400
- return;
401
- }
402
- users.push(entity);
403
- }));
440
+ for await (const user of client.getUsers(
441
+ {
442
+ filter: options.userFilter,
443
+ expand: options.userExpand
444
+ },
445
+ options.queryMode
446
+ )) {
447
+ promises.push(
448
+ limiter(async () => {
449
+ let userPhoto;
450
+ try {
451
+ userPhoto = await client.getUserPhotoWithSizeLimit(
452
+ user.id,
453
+ 120
454
+ );
455
+ } catch (e) {
456
+ options.logger.warn(`Unable to load photo for ${user.id}`);
457
+ }
458
+ const entity = await transformer(user, userPhoto);
459
+ if (!entity) {
460
+ return;
461
+ }
462
+ users.push(entity);
463
+ })
464
+ );
404
465
  }
405
466
  await Promise.all(promises);
406
467
  return { users };
@@ -413,48 +474,58 @@ async function readMicrosoftGraphUsersInGroups(client, options) {
413
474
  const userGroupMemberPromises = [];
414
475
  const userPromises = [];
415
476
  const groupMemberUsers = /* @__PURE__ */ new Set();
416
- for await (const group of client.getGroups({
417
- expand: options.groupExpand,
418
- search: options.userGroupMemberSearch,
419
- filter: options.userGroupMemberFilter
420
- }, options.queryMode)) {
421
- userGroupMemberPromises.push(limiter(async () => {
422
- for await (const member of client.getGroupMembers(group.id)) {
423
- if (!member.id) {
424
- continue;
425
- }
426
- if (member["@odata.type"] === "#microsoft.graph.user") {
427
- groupMemberUsers.add(member.id);
477
+ for await (const group of client.getGroups(
478
+ {
479
+ expand: options.groupExpand,
480
+ search: options.userGroupMemberSearch,
481
+ filter: options.userGroupMemberFilter
482
+ },
483
+ options.queryMode
484
+ )) {
485
+ userGroupMemberPromises.push(
486
+ limiter(async () => {
487
+ for await (const member of client.getGroupMembers(group.id)) {
488
+ if (!member.id) {
489
+ continue;
490
+ }
491
+ if (member["@odata.type"] === "#microsoft.graph.user") {
492
+ groupMemberUsers.add(member.id);
493
+ }
428
494
  }
429
- }
430
- }));
495
+ })
496
+ );
431
497
  }
432
498
  await Promise.all(userGroupMemberPromises);
433
499
  options.logger.info(`groupMemberUsers ${groupMemberUsers.size}`);
434
500
  for (const userId of groupMemberUsers) {
435
- userPromises.push(limiter(async () => {
436
- let user;
437
- let userPhoto;
438
- try {
439
- user = await client.getUserProfile(userId, {
440
- expand: options.userExpand
441
- });
442
- } catch (e) {
443
- options.logger.warn(`Unable to load user for ${userId}`);
444
- }
445
- if (user) {
501
+ userPromises.push(
502
+ limiter(async () => {
503
+ let user;
504
+ let userPhoto;
446
505
  try {
447
- userPhoto = await client.getUserPhotoWithSizeLimit(user.id, 120);
506
+ user = await client.getUserProfile(userId, {
507
+ expand: options.userExpand
508
+ });
448
509
  } catch (e) {
449
- options.logger.warn(`Unable to load userphoto for ${userId}`);
510
+ options.logger.warn(`Unable to load user for ${userId}`);
450
511
  }
451
- const entity = await transformer(user, userPhoto);
452
- if (!entity) {
453
- return;
512
+ if (user) {
513
+ try {
514
+ userPhoto = await client.getUserPhotoWithSizeLimit(
515
+ user.id,
516
+ 120
517
+ );
518
+ } catch (e) {
519
+ options.logger.warn(`Unable to load userphoto for ${userId}`);
520
+ }
521
+ const entity = await transformer(user, userPhoto);
522
+ if (!entity) {
523
+ return;
524
+ }
525
+ users.push(entity);
454
526
  }
455
- users.push(entity);
456
- }
457
- }));
527
+ })
528
+ );
458
529
  }
459
530
  await Promise.all(userPromises);
460
531
  return { users };
@@ -545,30 +616,35 @@ async function readMicrosoftGraphGroups(client, tenantId, options) {
545
616
  }
546
617
  const transformer = (_a = options == null ? void 0 : options.groupTransformer) != null ? _a : defaultGroupTransformer;
547
618
  const promises = [];
548
- for await (const group of client.getGroups({
549
- expand: options == null ? void 0 : options.groupExpand,
550
- search: options == null ? void 0 : options.groupSearch,
551
- filter: options == null ? void 0 : options.groupFilter,
552
- select: options == null ? void 0 : options.groupSelect
553
- }, options == null ? void 0 : options.queryMode)) {
554
- promises.push(limiter(async () => {
555
- const entity = await transformer(group);
556
- if (!entity) {
557
- return;
558
- }
559
- for await (const member of client.getGroupMembers(group.id)) {
560
- if (!member.id) {
561
- continue;
562
- }
563
- if (member["@odata.type"] === "#microsoft.graph.user") {
564
- ensureItem(groupMemberOf, member.id, group.id);
619
+ for await (const group of client.getGroups(
620
+ {
621
+ expand: options == null ? void 0 : options.groupExpand,
622
+ search: options == null ? void 0 : options.groupSearch,
623
+ filter: options == null ? void 0 : options.groupFilter,
624
+ select: options == null ? void 0 : options.groupSelect
625
+ },
626
+ options == null ? void 0 : options.queryMode
627
+ )) {
628
+ promises.push(
629
+ limiter(async () => {
630
+ const entity = await transformer(group);
631
+ if (!entity) {
632
+ return;
565
633
  }
566
- if (member["@odata.type"] === "#microsoft.graph.group") {
567
- ensureItem(groupMember, group.id, member.id);
634
+ for await (const member of client.getGroupMembers(group.id)) {
635
+ if (!member.id) {
636
+ continue;
637
+ }
638
+ if (member["@odata.type"] === "#microsoft.graph.user") {
639
+ ensureItem(groupMemberOf, member.id, group.id);
640
+ }
641
+ if (member["@odata.type"] === "#microsoft.graph.group") {
642
+ ensureItem(groupMember, group.id, member.id);
643
+ }
568
644
  }
569
- }
570
- groups.push(entity);
571
- }));
645
+ groups.push(entity);
646
+ })
647
+ );
572
648
  }
573
649
  await Promise.all(promises);
574
650
  return {
@@ -582,14 +658,22 @@ function resolveRelations(rootGroup, groups, users, groupMember, groupMemberOf)
582
658
  const groupMap = /* @__PURE__ */ new Map();
583
659
  for (const group of groups) {
584
660
  if (group.metadata.annotations[MICROSOFT_GRAPH_GROUP_ID_ANNOTATION]) {
585
- groupMap.set(group.metadata.annotations[MICROSOFT_GRAPH_GROUP_ID_ANNOTATION], group);
661
+ groupMap.set(
662
+ group.metadata.annotations[MICROSOFT_GRAPH_GROUP_ID_ANNOTATION],
663
+ group
664
+ );
586
665
  }
587
666
  if (group.metadata.annotations[MICROSOFT_GRAPH_TENANT_ID_ANNOTATION]) {
588
- groupMap.set(group.metadata.annotations[MICROSOFT_GRAPH_TENANT_ID_ANNOTATION], group);
667
+ groupMap.set(
668
+ group.metadata.annotations[MICROSOFT_GRAPH_TENANT_ID_ANNOTATION],
669
+ group
670
+ );
589
671
  }
590
672
  }
591
673
  const parentGroups = /* @__PURE__ */ new Map();
592
- groupMember.forEach((members, groupId) => members.forEach((m) => ensureItem(parentGroups, m, groupId)));
674
+ groupMember.forEach(
675
+ (members, groupId) => members.forEach((m) => ensureItem(parentGroups, m, groupId))
676
+ );
593
677
  if (rootGroup) {
594
678
  const tenantId = rootGroup.metadata.annotations[MICROSOFT_GRAPH_TENANT_ID_ANNOTATION];
595
679
  groups.forEach((group) => {
@@ -637,13 +721,16 @@ function resolveRelations(rootGroup, groups, users, groupMember, groupMemberOf)
637
721
  async function readMicrosoftGraphOrg(client, tenantId, options) {
638
722
  const users = [];
639
723
  if (options.userGroupMemberFilter || options.userGroupMemberSearch) {
640
- const { users: usersInGroups } = await readMicrosoftGraphUsersInGroups(client, {
641
- queryMode: options.queryMode,
642
- userGroupMemberFilter: options.userGroupMemberFilter,
643
- userGroupMemberSearch: options.userGroupMemberSearch,
644
- transformer: options.userTransformer,
645
- logger: options.logger
646
- });
724
+ const { users: usersInGroups } = await readMicrosoftGraphUsersInGroups(
725
+ client,
726
+ {
727
+ queryMode: options.queryMode,
728
+ userGroupMemberFilter: options.userGroupMemberFilter,
729
+ userGroupMemberSearch: options.userGroupMemberSearch,
730
+ transformer: options.userTransformer,
731
+ logger: options.logger
732
+ }
733
+ );
647
734
  users.push(...usersInGroups);
648
735
  } else {
649
736
  const { users: usersWithFilter } = await readMicrosoftGraphUsers(client, {
@@ -702,21 +789,36 @@ class MicrosoftGraphOrgEntityProvider {
702
789
  id: providerConfig.id,
703
790
  provider: providerConfig,
704
791
  logger: options.logger,
705
- userTransformer: getTransformer(providerConfig.id, options.userTransformer),
706
- groupTransformer: getTransformer(providerConfig.id, options.groupTransformer),
707
- organizationTransformer: getTransformer(providerConfig.id, options.organizationTransformer)
792
+ userTransformer: getTransformer(
793
+ providerConfig.id,
794
+ options.userTransformer
795
+ ),
796
+ groupTransformer: getTransformer(
797
+ providerConfig.id,
798
+ options.groupTransformer
799
+ ),
800
+ organizationTransformer: getTransformer(
801
+ providerConfig.id,
802
+ options.organizationTransformer
803
+ )
708
804
  });
709
805
  provider.schedule(options.schedule);
710
806
  return provider;
711
807
  });
712
808
  }
713
809
  static fromLegacyConfig(configRoot, options) {
714
- options.logger.warn('Deprecated msgraph config "catalog.processors.microsoftGraphOrg" used. Use "catalog.providers.microsoftGraphOrg" instead. More info at https://github.com/backstage/backstage/blob/master/.changeset/long-bananas-rescue.md');
715
- const config = configRoot.getOptionalConfig("catalog.processors.microsoftGraphOrg");
810
+ options.logger.warn(
811
+ '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'
812
+ );
813
+ const config = configRoot.getOptionalConfig(
814
+ "catalog.processors.microsoftGraphOrg"
815
+ );
716
816
  const providers = config ? readMicrosoftGraphConfig(config) : [];
717
817
  const provider = providers.find((p) => options.target.startsWith(p.target));
718
818
  if (!provider) {
719
- throw new Error(`There is no Microsoft Graph Org provider that matches "${options.target}". Please add a configuration entry for it under "catalog.processors.microsoftGraphOrg.providers".`);
819
+ throw new Error(
820
+ `There is no Microsoft Graph Org provider that matches "${options.target}". Please add a configuration entry for it under "catalog.processors.microsoftGraphOrg.providers".`
821
+ );
720
822
  }
721
823
  const logger = options.logger.child({
722
824
  target: options.target
@@ -749,19 +851,23 @@ class MicrosoftGraphOrgEntityProvider {
749
851
  const provider = this.options.provider;
750
852
  const { markReadComplete } = trackProgress(logger);
751
853
  const client = MicrosoftGraphClient.create(this.options.provider);
752
- const { users, groups } = await readMicrosoftGraphOrg(client, provider.tenantId, {
753
- userFilter: provider.userFilter,
754
- userGroupMemberFilter: provider.userGroupMemberFilter,
755
- userGroupMemberSearch: provider.userGroupMemberSearch,
756
- groupFilter: provider.groupFilter,
757
- groupSearch: provider.groupSearch,
758
- groupSelect: provider.groupSelect,
759
- queryMode: provider.queryMode,
760
- groupTransformer: this.options.groupTransformer,
761
- userTransformer: this.options.userTransformer,
762
- organizationTransformer: this.options.organizationTransformer,
763
- logger
764
- });
854
+ const { users, groups } = await readMicrosoftGraphOrg(
855
+ client,
856
+ provider.tenantId,
857
+ {
858
+ userFilter: provider.userFilter,
859
+ userGroupMemberFilter: provider.userGroupMemberFilter,
860
+ userGroupMemberSearch: provider.userGroupMemberSearch,
861
+ groupFilter: provider.groupFilter,
862
+ groupSearch: provider.groupSearch,
863
+ groupSelect: provider.groupSelect,
864
+ queryMode: provider.queryMode,
865
+ groupTransformer: this.options.groupTransformer,
866
+ userTransformer: this.options.userTransformer,
867
+ organizationTransformer: this.options.organizationTransformer,
868
+ logger
869
+ }
870
+ );
765
871
  const { markCommitComplete } = markReadComplete({ users, groups });
766
872
  await this.connection.applyMutation({
767
873
  type: "full",
@@ -817,14 +923,17 @@ function withLocations(providerId, entity) {
817
923
  var _a, _b, _c;
818
924
  const uid = ((_a = entity.metadata.annotations) == null ? void 0 : _a[MICROSOFT_GRAPH_USER_ID_ANNOTATION]) || ((_b = entity.metadata.annotations) == null ? void 0 : _b[MICROSOFT_GRAPH_GROUP_ID_ANNOTATION]) || ((_c = entity.metadata.annotations) == null ? void 0 : _c[MICROSOFT_GRAPH_TENANT_ID_ANNOTATION]) || entity.metadata.name;
819
925
  const location = `msgraph:${providerId}/${encodeURIComponent(uid)}`;
820
- return lodash.merge({
821
- metadata: {
822
- annotations: {
823
- [catalogModel.ANNOTATION_LOCATION]: location,
824
- [catalogModel.ANNOTATION_ORIGIN_LOCATION]: location
926
+ return lodash.merge(
927
+ {
928
+ metadata: {
929
+ annotations: {
930
+ [catalogModel.ANNOTATION_LOCATION]: location,
931
+ [catalogModel.ANNOTATION_ORIGIN_LOCATION]: location
932
+ }
825
933
  }
826
- }
827
- }, entity);
934
+ },
935
+ entity
936
+ );
828
937
  }
829
938
 
830
939
  class MicrosoftGraphOrgReaderProcessor {
@@ -836,7 +945,9 @@ class MicrosoftGraphOrgReaderProcessor {
836
945
  });
837
946
  }
838
947
  constructor(options) {
839
- options.logger.warn("MicrosoftGraphOrgReaderProcessor is deprecated. Please use MicrosoftGraphOrgEntityProvider instead. More info at https://github.com/backstage/backstage/blob/master/.changeset/long-bananas-rescue.md");
948
+ options.logger.warn(
949
+ "MicrosoftGraphOrgReaderProcessor is deprecated. Please use MicrosoftGraphOrgEntityProvider instead. More info at https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-msgraph/CHANGELOG.md#040-next1"
950
+ );
840
951
  this.providers = options.providers;
841
952
  this.logger = options.logger;
842
953
  this.userTransformer = options.userTransformer;
@@ -850,30 +961,40 @@ class MicrosoftGraphOrgReaderProcessor {
850
961
  if (location.type !== "microsoft-graph-org") {
851
962
  return false;
852
963
  }
853
- const provider = this.providers.find((p) => location.target.startsWith(p.target));
964
+ const provider = this.providers.find(
965
+ (p) => location.target.startsWith(p.target)
966
+ );
854
967
  if (!provider) {
855
- throw new Error(`There is no Microsoft Graph Org provider that matches ${location.target}. Please add a configuration entry for it under catalog.processors.microsoftGraphOrg.providers.`);
968
+ throw new Error(
969
+ `There is no Microsoft Graph Org provider that matches ${location.target}. Please add a configuration entry for it under catalog.processors.microsoftGraphOrg.providers.`
970
+ );
856
971
  }
857
972
  const startTimestamp = Date.now();
858
973
  this.logger.info("Reading Microsoft Graph users and groups");
859
974
  const client = MicrosoftGraphClient.create(provider);
860
- const { users, groups } = await readMicrosoftGraphOrg(client, provider.tenantId, {
861
- userExpand: provider.userExpand,
862
- userFilter: provider.userFilter,
863
- userGroupMemberFilter: provider.userGroupMemberFilter,
864
- userGroupMemberSearch: provider.userGroupMemberSearch,
865
- groupExpand: provider.groupExpand,
866
- groupFilter: provider.groupFilter,
867
- groupSearch: provider.groupSearch,
868
- groupSelect: provider.groupSelect,
869
- queryMode: provider.queryMode,
870
- userTransformer: this.userTransformer,
871
- groupTransformer: this.groupTransformer,
872
- organizationTransformer: this.organizationTransformer,
873
- logger: this.logger
874
- });
975
+ const { users, groups } = await readMicrosoftGraphOrg(
976
+ client,
977
+ provider.tenantId,
978
+ {
979
+ userExpand: provider.userExpand,
980
+ userFilter: provider.userFilter,
981
+ userGroupMemberFilter: provider.userGroupMemberFilter,
982
+ userGroupMemberSearch: provider.userGroupMemberSearch,
983
+ groupExpand: provider.groupExpand,
984
+ groupFilter: provider.groupFilter,
985
+ groupSearch: provider.groupSearch,
986
+ groupSelect: provider.groupSelect,
987
+ queryMode: provider.queryMode,
988
+ userTransformer: this.userTransformer,
989
+ groupTransformer: this.groupTransformer,
990
+ organizationTransformer: this.organizationTransformer,
991
+ logger: this.logger
992
+ }
993
+ );
875
994
  const duration = ((Date.now() - startTimestamp) / 1e3).toFixed(1);
876
- this.logger.debug(`Read ${users.length} users and ${groups.length} groups from Microsoft Graph in ${duration} seconds`);
995
+ this.logger.debug(
996
+ `Read ${users.length} users and ${groups.length} groups from Microsoft Graph in ${duration} seconds`
997
+ );
877
998
  for (const group of groups) {
878
999
  emit(pluginCatalogBackend.processingResult.entity(location, group));
879
1000
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/microsoftGraph/client.ts","../src/microsoftGraph/config.ts","../src/microsoftGraph/constants.ts","../src/microsoftGraph/helper.ts","../src/microsoftGraph/org.ts","../src/microsoftGraph/read.ts","../src/processors/MicrosoftGraphOrgEntityProvider.ts","../src/processors/MicrosoftGraphOrgReaderProcessor.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 fetch, { Response } from 'node-fetch';\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\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.user' })\n | (MicrosoftGraph.User & { '@odata.type': '#microsoft.graph.group' });\n\n/**\n * A HTTP Client that communicates with Microsoft Graph API.\n * Simplify Authentication and API calls to get `User` and `Group` from Azure Active Directory\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 constructor(\n private readonly baseUrl: string,\n private readonly 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 },\n {\n addQueryPrefix: true,\n // Microsoft Graph doesn't like an encoded query string\n encode: false,\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 ): Promise<Response> {\n // Make sure that we always have a valid access token (might be cached)\n const token = await this.tokenCredential.getToken(\n 'https://graph.microsoft.com/.default',\n );\n\n if (!token) {\n throw new Error('Failed to obtain token from Azure Identity');\n }\n\n return await fetch(url, {\n headers: {\n ...headers,\n Authorization: `Bearer ${token.token}`,\n },\n });\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User}\n * from Graph API\n *\n * @public\n * @param userId - The unique identifier for the `User` resource\n * @param query - OData Query {@link ODataQuery}\n *\n */\n async getUserProfile(\n userId: string,\n query?: ODataQuery,\n ): Promise<MicrosoftGraph.User> {\n const response = await this.requestApi(`users/${userId}`, query);\n\n if (response.status !== 200) {\n await this.handleError('user profile', 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 * 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 */\n async *getUsers(\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n ): AsyncIterable<MicrosoftGraph.User> {\n yield* this.requestCollection<MicrosoftGraph.User>(\n `users`,\n query,\n queryMode,\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 */\n async *getGroups(\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n ): AsyncIterable<MicrosoftGraph.Group> {\n yield* this.requestCollection<MicrosoftGraph.Group>(\n `groups`,\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 *\n */\n async *getGroupMembers(groupId: string): AsyncIterable<GroupMember> {\n yield* this.requestCollection<GroupMember>(`groups/${groupId}/members`);\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 {@link entityName | 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","/*\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 { Config } from '@backstage/config';\nimport { trimEnd } from 'lodash';\n\nconst DEFAULT_PROVIDER_ID = 'default';\nconst DEFAULT_TARGET = 'https://graph.microsoft.com/v1.0';\n\n/**\n * The configuration parameters for a single Microsoft Graph provider.\n *\n * @public\n */\nexport type MicrosoftGraphProviderConfig = {\n /**\n * Identifier of the provider which will be used i.e. at the location key for ingested entities.\n */\n id: string;\n\n /**\n * The prefix of the target that this matches on, e.g.\n * \"https://graph.microsoft.com/v1.0\", with no trailing slash.\n */\n target: string;\n /**\n * The auth authority used.\n *\n * E.g. \"https://login.microsoftonline.com\"\n */\n authority?: string;\n /**\n * The tenant whose org data we are interested in.\n */\n tenantId: string;\n /**\n * The OAuth client ID to use for authenticating requests.\n * If specified, ClientSecret must also be specified\n */\n clientId?: string;\n /**\n * The OAuth client secret to use for authenticating requests.\n * If specified, ClientId must also be specified\n */\n clientSecret?: string;\n /**\n * The filter to apply to extract users.\n *\n * E.g. \"accountEnabled eq true and userType eq 'member'\"\n */\n userFilter?: string;\n /**\n * The \"expand\" argument to apply to users.\n *\n * E.g. \"manager\".\n */\n userExpand?: string;\n /**\n * The filter to apply to extract users by groups memberships.\n *\n * E.g. \"displayName eq 'Backstage Users'\"\n */\n userGroupMemberFilter?: string;\n /**\n * The search criteria to apply to extract users by groups memberships.\n *\n * E.g. \"\\\"displayName:-team\\\"\" would only match groups which contain '-team'\n */\n userGroupMemberSearch?: string;\n /**\n * The \"expand\" argument to apply to groups.\n *\n * E.g. \"member\".\n */\n groupExpand?: string;\n /**\n * The filter to apply to extract groups.\n *\n * E.g. \"securityEnabled eq false and mailEnabled eq true\"\n */\n groupFilter?: string;\n /**\n * The search criteria to apply to extract groups.\n *\n * E.g. \"\\\"displayName:-team\\\"\" would only match groups which contain '-team'\n */\n groupSearch?: string;\n\n /**\n * The fields to be fetched on query.\n *\n * E.g. [\"id\", \"displayName\", \"description\"]\n */\n groupSelect?: string[];\n\n /**\n * By default, the Microsoft Graph API only provides the basic feature set\n * for querying. Certain features are limited to advanced query capabilities\n * (see https://docs.microsoft.com/en-us/graph/aad-advanced-queries)\n * and need to be enabled.\n *\n * Some features like `$expand` are not available for advanced queries, though.\n */\n queryMode?: 'basic' | 'advanced';\n};\n\n/**\n * Parses configuration.\n *\n * @param config - The root of the msgraph config hierarchy\n *\n * @public\n * @deprecated Replaced by not exported `readProviderConfigs` and kept for backwards compatibility only.\n */\nexport function readMicrosoftGraphConfig(\n config: Config,\n): MicrosoftGraphProviderConfig[] {\n const providers: MicrosoftGraphProviderConfig[] = [];\n const providerConfigs = config.getOptionalConfigArray('providers') ?? [];\n\n for (const providerConfig of providerConfigs) {\n const target = trimEnd(\n providerConfig.getOptionalString('target') ?? DEFAULT_TARGET,\n '/',\n );\n const authority = providerConfig.getOptionalString('authority');\n\n const tenantId = providerConfig.getString('tenantId');\n const clientId = providerConfig.getOptionalString('clientId');\n const clientSecret = providerConfig.getOptionalString('clientSecret');\n\n const userExpand = providerConfig.getOptionalString('userExpand');\n const userFilter = providerConfig.getOptionalString('userFilter');\n const userGroupMemberFilter = providerConfig.getOptionalString(\n 'userGroupMemberFilter',\n );\n const userGroupMemberSearch = providerConfig.getOptionalString(\n 'userGroupMemberSearch',\n );\n const groupExpand = providerConfig.getOptionalString('groupExpand');\n const groupFilter = providerConfig.getOptionalString('groupFilter');\n const groupSearch = providerConfig.getOptionalString('groupSearch');\n\n if (userFilter && userGroupMemberFilter) {\n throw new Error(\n `userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.`,\n );\n }\n if (userFilter && userGroupMemberSearch) {\n throw new Error(\n `userGroupMemberSearch cannot be specified when userFilter is defined.`,\n );\n }\n\n const groupSelect = providerConfig.getOptionalStringArray('groupSelect');\n const queryMode = providerConfig.getOptionalString('queryMode');\n if (\n queryMode !== undefined &&\n queryMode !== 'basic' &&\n queryMode !== 'advanced'\n ) {\n throw new Error(`queryMode must be one of: basic, advanced`);\n }\n\n if (clientId && !clientSecret) {\n throw new Error(\n `clientSecret must be provided when clientId is defined.`,\n );\n }\n\n if (clientSecret && !clientId) {\n throw new Error(\n `clientId must be provided when clientSecret is defined.`,\n );\n }\n\n providers.push({\n id: target,\n target,\n authority,\n tenantId,\n clientId,\n clientSecret,\n userExpand,\n userFilter,\n userGroupMemberFilter,\n userGroupMemberSearch,\n groupExpand,\n groupFilter,\n groupSearch,\n groupSelect,\n queryMode,\n });\n }\n\n return providers;\n}\n\nexport function readProviderConfigs(\n config: Config,\n): MicrosoftGraphProviderConfig[] {\n const providersConfig = config.getOptionalConfig(\n 'catalog.providers.microsoftGraphOrg',\n );\n if (!providersConfig) {\n return [];\n }\n\n if (providersConfig.has('clientId')) {\n // simple/single config variant\n return [readProviderConfig(DEFAULT_PROVIDER_ID, providersConfig)];\n }\n\n return providersConfig.keys().map(id => {\n const providerConfig = providersConfig.getConfig(id);\n\n return readProviderConfig(id, providerConfig);\n });\n}\n\nexport function readProviderConfig(\n id: string,\n config: Config,\n): MicrosoftGraphProviderConfig {\n const target = trimEnd(\n config.getOptionalString('target') ?? DEFAULT_TARGET,\n '/',\n );\n const authority = config.getOptionalString('authority');\n\n const tenantId = config.getString('tenantId');\n const clientId = config.getOptionalString('clientId');\n const clientSecret = config.getOptionalString('clientSecret');\n\n const userExpand = config.getOptionalString('user.expand');\n const userFilter = config.getOptionalString('user.filter');\n\n const groupExpand = config.getOptionalString('group.expand');\n const groupFilter = config.getOptionalString('group.filter');\n const groupSearch = config.getOptionalString('group.search');\n const groupSelect = config.getOptionalStringArray('group.select');\n\n const userGroupMemberFilter = config.getOptionalString(\n 'userGroupMember.filter',\n );\n const userGroupMemberSearch = config.getOptionalString(\n 'userGroupMember.search',\n );\n\n if (userFilter && userGroupMemberFilter) {\n throw new Error(\n `userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.`,\n );\n }\n if (userFilter && userGroupMemberSearch) {\n throw new Error(\n `userGroupMemberSearch cannot be specified when userFilter is defined.`,\n );\n }\n\n if (clientId && !clientSecret) {\n throw new Error(`clientSecret must be provided when clientId is defined.`);\n }\n\n if (clientSecret && !clientId) {\n throw new Error(`clientId must be provided when clientSecret is defined.`);\n }\n\n return {\n id,\n target,\n authority,\n clientId,\n clientSecret,\n tenantId,\n userExpand,\n userFilter,\n groupExpand,\n groupFilter,\n groupSearch,\n groupSelect,\n userGroupMemberFilter,\n userGroupMemberSearch,\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The (primary) user email. Also used by the Microsoft auth provider to resolve the User entity.\n *\n * @public\n */\nexport const MICROSOFT_EMAIL_ANNOTATION = 'microsoft.com/email';\n\n/**\n * The tenant id used by the Microsoft Graph API\n *\n * @public\n */\nexport const MICROSOFT_GRAPH_TENANT_ID_ANNOTATION =\n 'graph.microsoft.com/tenant-id';\n\n/**\n * The group id used by the Microsoft Graph API\n *\n * @public\n */\nexport const MICROSOFT_GRAPH_GROUP_ID_ANNOTATION =\n 'graph.microsoft.com/group-id';\n\n/**\n * The user id used by the Microsoft Graph API\n *\n * @public\n */\nexport const MICROSOFT_GRAPH_USER_ID_ANNOTATION = 'graph.microsoft.com/user-id';\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Takes an input string and cleans it up to become suitable as an entity name.\n *\n * @public\n */\nexport function normalizeEntityName(name: string): string {\n let cleaned = name\n .trim()\n .toLocaleLowerCase()\n .replace(/[^a-zA-Z0-9_\\-\\.]/g, '_');\n\n // invalid to end with _\n while (cleaned.endsWith('_')) {\n cleaned = cleaned.substring(0, cleaned.length - 1);\n }\n\n // cleans up format for groups like 'my group (Reader)'\n while (cleaned.includes('__')) {\n // replaceAll from node.js >= 15\n cleaned = cleaned.replace('__', '_');\n }\n\n return cleaned;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { GroupEntity, UserEntity } from '@backstage/catalog-model';\n\n// TODO: Copied from plugin-catalog-backend, but we could also export them from\n// there. Or move them to catalog-model.\n\nexport function buildOrgHierarchy(groups: GroupEntity[]) {\n const groupsByName = new Map(groups.map(g => [g.metadata.name, g]));\n\n //\n // Make sure that g.parent.children contain g\n //\n\n for (const group of groups) {\n const selfName = group.metadata.name;\n const parentName = group.spec.parent;\n if (parentName) {\n const parent = groupsByName.get(parentName);\n if (parent && !parent.spec.children.includes(selfName)) {\n parent.spec.children.push(selfName);\n }\n }\n }\n\n //\n // Make sure that g.children.parent is g\n //\n\n for (const group of groups) {\n const selfName = group.metadata.name;\n for (const childName of group.spec.children) {\n const child = groupsByName.get(childName);\n if (child && !child.spec.parent) {\n child.spec.parent = selfName;\n }\n }\n }\n}\n\n// Ensure that users have their transitive group memberships. Requires that\n// the groups were previously processed with buildOrgHierarchy()\nexport function buildMemberOf(groups: GroupEntity[], users: UserEntity[]) {\n const groupsByName = new Map(groups.map(g => [g.metadata.name, g]));\n\n users.forEach(user => {\n const transitiveMemberOf = new Set<string>();\n\n const todo = [\n ...(user.spec.memberOf ?? []),\n ...groups\n .filter(g => g.spec.members?.includes(user.metadata.name))\n .map(g => g.metadata.name),\n ];\n\n for (;;) {\n const current = todo.pop();\n if (!current) {\n break;\n }\n\n if (!transitiveMemberOf.has(current)) {\n transitiveMemberOf.add(current);\n const group = groupsByName.get(current);\n if (group?.spec.parent) {\n todo.push(group.spec.parent);\n }\n }\n }\n\n user.spec.memberOf = [...transitiveMemberOf];\n });\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n GroupEntity,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport * as MicrosoftGraph from '@microsoft/microsoft-graph-types';\nimport limiterFactory from 'p-limit';\nimport { Logger } from 'winston';\nimport { MicrosoftGraphClient } from './client';\nimport {\n MICROSOFT_EMAIL_ANNOTATION,\n MICROSOFT_GRAPH_GROUP_ID_ANNOTATION,\n MICROSOFT_GRAPH_TENANT_ID_ANNOTATION,\n MICROSOFT_GRAPH_USER_ID_ANNOTATION,\n} from './constants';\nimport { normalizeEntityName } from './helper';\nimport { buildMemberOf, buildOrgHierarchy } from './org';\nimport {\n GroupTransformer,\n OrganizationTransformer,\n UserTransformer,\n} from './types';\n\n/**\n * The default implementation of the transformation from a graph user entry to\n * a User entity.\n *\n * @public\n */\nexport async function defaultUserTransformer(\n user: MicrosoftGraph.User,\n userPhoto?: string,\n): Promise<UserEntity | undefined> {\n if (!user.id || !user.displayName || !user.mail) {\n return undefined;\n }\n\n const name = normalizeEntityName(user.mail);\n const entity: UserEntity = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'User',\n metadata: {\n name,\n annotations: {\n [MICROSOFT_EMAIL_ANNOTATION]: user.mail!,\n [MICROSOFT_GRAPH_USER_ID_ANNOTATION]: user.id!,\n },\n },\n spec: {\n profile: {\n displayName: user.displayName!,\n email: user.mail!,\n\n // TODO: Additional fields?\n // jobTitle: user.jobTitle || undefined,\n // officeLocation: user.officeLocation || undefined,\n // mobilePhone: user.mobilePhone || undefined,\n },\n memberOf: [],\n },\n };\n\n if (userPhoto) {\n entity.spec.profile!.picture = userPhoto;\n }\n\n return entity;\n}\n\nexport async function readMicrosoftGraphUsers(\n client: MicrosoftGraphClient,\n options: {\n queryMode?: 'basic' | 'advanced';\n userFilter?: string;\n userExpand?: string;\n transformer?: UserTransformer;\n logger: Logger;\n },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n}> {\n const users: UserEntity[] = [];\n const limiter = limiterFactory(10);\n\n const transformer = options.transformer ?? defaultUserTransformer;\n const promises: Promise<void>[] = [];\n\n for await (const user of client.getUsers(\n {\n filter: options.userFilter,\n expand: options.userExpand,\n },\n options.queryMode,\n )) {\n // Process all users in parallel, otherwise it can take quite some time\n promises.push(\n limiter(async () => {\n let userPhoto;\n try {\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 } catch (e) {\n options.logger.warn(`Unable to load photo for ${user.id}`);\n }\n\n const entity = await transformer(user, userPhoto);\n\n if (!entity) {\n return;\n }\n\n users.push(entity);\n }),\n );\n }\n\n // Wait for all users and photos to be downloaded\n await Promise.all(promises);\n\n return { users };\n}\n\nexport async function readMicrosoftGraphUsersInGroups(\n client: MicrosoftGraphClient,\n options: {\n queryMode?: 'basic' | 'advanced';\n userExpand?: string;\n userGroupMemberSearch?: string;\n userGroupMemberFilter?: string;\n groupExpand?: string;\n transformer?: UserTransformer;\n logger: Logger;\n },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n}> {\n const users: UserEntity[] = [];\n\n const limiter = limiterFactory(10);\n\n const transformer = options.transformer ?? defaultUserTransformer;\n const userGroupMemberPromises: Promise<void>[] = [];\n const userPromises: Promise<void>[] = [];\n\n const groupMemberUsers: Set<string> = new Set();\n\n for await (const group of client.getGroups(\n {\n expand: options.groupExpand,\n search: options.userGroupMemberSearch,\n filter: options.userGroupMemberFilter,\n },\n options.queryMode,\n )) {\n // Process all groups in parallel, otherwise it can take quite some time\n userGroupMemberPromises.push(\n limiter(async () => {\n for await (const member of client.getGroupMembers(group.id!)) {\n if (!member.id) {\n continue;\n }\n\n if (member['@odata.type'] === '#microsoft.graph.user') {\n groupMemberUsers.add(member.id);\n }\n }\n }),\n );\n }\n\n // Wait for all group members\n await Promise.all(userGroupMemberPromises);\n\n options.logger.info(`groupMemberUsers ${groupMemberUsers.size}`);\n for (const userId of groupMemberUsers) {\n // Process all users in parallel, otherwise it can take quite some time\n userPromises.push(\n limiter(async () => {\n let user;\n let userPhoto;\n try {\n user = await client.getUserProfile(userId, {\n expand: options.userExpand,\n });\n } catch (e) {\n options.logger.warn(`Unable to load user for ${userId}`);\n }\n if (user) {\n try {\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 } catch (e) {\n options.logger.warn(`Unable to load userphoto for ${userId}`);\n }\n\n const entity = await transformer(user, userPhoto);\n\n if (!entity) {\n return;\n }\n users.push(entity);\n }\n }),\n );\n }\n\n // Wait for all users and photos to be downloaded\n await Promise.all(userPromises);\n\n return { users };\n}\n\n/**\n * The default implementation of the transformation from a graph organization\n * entry to a Group entity.\n *\n * @public\n */\nexport async function defaultOrganizationTransformer(\n organization: MicrosoftGraph.Organization,\n): Promise<GroupEntity | undefined> {\n if (!organization.id || !organization.displayName) {\n return undefined;\n }\n\n const name = normalizeEntityName(organization.displayName!);\n return {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Group',\n metadata: {\n name: name,\n description: organization.displayName!,\n annotations: {\n [MICROSOFT_GRAPH_TENANT_ID_ANNOTATION]: organization.id!,\n },\n },\n spec: {\n type: 'root',\n profile: {\n displayName: organization.displayName!,\n },\n children: [],\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\nfunction extractGroupName(group: MicrosoftGraph.Group): string {\n if (group.securityEnabled) {\n return group.displayName as string;\n }\n return (group.mailNickname || group.displayName) as string;\n}\n\n/**\n * The default implementation of the transformation from a graph group entry to\n * a Group entity.\n *\n * @public\n */\nexport async function defaultGroupTransformer(\n group: MicrosoftGraph.Group,\n groupPhoto?: string,\n): Promise<GroupEntity | undefined> {\n if (!group.id || !group.displayName) {\n return undefined;\n }\n\n const name = normalizeEntityName(extractGroupName(group));\n const entity: GroupEntity = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Group',\n metadata: {\n name: name,\n annotations: {\n [MICROSOFT_GRAPH_GROUP_ID_ANNOTATION]: group.id,\n },\n },\n spec: {\n type: 'team',\n profile: {},\n children: [],\n },\n };\n\n if (group.description) {\n entity.metadata.description = group.description;\n }\n if (group.displayName) {\n entity.spec.profile!.displayName = group.displayName;\n }\n if (group.mail) {\n entity.spec.profile!.email = group.mail;\n }\n if (groupPhoto) {\n entity.spec.profile!.picture = groupPhoto;\n }\n\n return entity;\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 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 search: options?.groupSearch,\n filter: options?.groupFilter,\n select: options?.groupSelect,\n },\n options?.queryMode,\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 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 }\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 the 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 retrieveItems(parentGroups, id).forEach(p => {\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 userGroupMemberSearch?: string;\n userGroupMemberFilter?: string;\n groupExpand?: string;\n groupSearch?: string;\n groupFilter?: string;\n groupSelect?: string[];\n queryMode?: 'basic' | 'advanced';\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n logger: Logger;\n },\n): Promise<{ users: UserEntity[]; groups: GroupEntity[] }> {\n const users: UserEntity[] = [];\n\n if (options.userGroupMemberFilter || options.userGroupMemberSearch) {\n const { users: usersInGroups } = await readMicrosoftGraphUsersInGroups(\n client,\n {\n queryMode: options.queryMode,\n userGroupMemberFilter: options.userGroupMemberFilter,\n userGroupMemberSearch: options.userGroupMemberSearch,\n transformer: options.userTransformer,\n logger: options.logger,\n },\n );\n users.push(...usersInGroups);\n } else {\n const { users: usersWithFilter } = await readMicrosoftGraphUsers(client, {\n queryMode: options.queryMode,\n userFilter: options.userFilter,\n userExpand: options.userExpand,\n transformer: options.userTransformer,\n logger: options.logger,\n });\n users.push(...usersWithFilter);\n }\n const { groups, rootGroup, groupMember, groupMemberOf } =\n await readMicrosoftGraphGroups(client, tenantId, {\n queryMode: options.queryMode,\n groupSearch: options.groupSearch,\n groupFilter: options.groupFilter,\n groupSelect: options.groupSelect,\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\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 target.get(key) ?? new Set();\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TaskRunner } from '@backstage/backend-tasks';\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-backend';\nimport { merge } from 'lodash';\nimport * as uuid from 'uuid';\nimport { Logger } from 'winston';\nimport {\n GroupTransformer,\n MicrosoftGraphClient,\n MicrosoftGraphProviderConfig,\n MICROSOFT_GRAPH_GROUP_ID_ANNOTATION,\n MICROSOFT_GRAPH_TENANT_ID_ANNOTATION,\n MICROSOFT_GRAPH_USER_ID_ANNOTATION,\n OrganizationTransformer,\n readMicrosoftGraphConfig,\n readMicrosoftGraphOrg,\n UserTransformer,\n} from '../microsoftGraph';\nimport { readProviderConfigs } from '../microsoftGraph/config';\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: Logger;\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-tasks#PluginTaskScheduler.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule: 'manual' | TaskRunner;\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/**\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: Logger;\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-tasks#PluginTaskScheduler.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule: 'manual' | TaskRunner;\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/**\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 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 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 });\n provider.schedule(options.schedule);\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/.changeset/long-bananas-rescue.md',\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 logger,\n provider,\n });\n\n result.schedule(options.schedule);\n\n return result;\n }\n\n constructor(\n private options: {\n id: string;\n provider: MicrosoftGraphProviderConfig;\n logger: Logger;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n },\n ) {}\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getProviderName} */\n getProviderName() {\n return `MicrosoftGraphOrgEntityProvider:${this.options.id}`;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#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?: Logger }) {\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.provider;\n const { markReadComplete } = trackProgress(logger);\n const client = MicrosoftGraphClient.create(this.options.provider);\n const { users, groups } = await readMicrosoftGraphOrg(\n client,\n provider.tenantId,\n {\n userFilter: provider.userFilter,\n userGroupMemberFilter: provider.userGroupMemberFilter,\n userGroupMemberSearch: provider.userGroupMemberSearch,\n groupFilter: provider.groupFilter,\n groupSearch: provider.groupSearch,\n groupSelect: provider.groupSelect,\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({ users, groups });\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();\n }\n\n private schedule(\n schedule: MicrosoftGraphOrgEntityProviderOptions['schedule'],\n ) {\n if (schedule === 'manual') {\n return;\n }\n\n this.scheduleFn = async () => {\n const id = `${this.getProviderName()}:refresh`;\n await schedule.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(error);\n }\n },\n });\n };\n }\n}\n\n// Helps wrap the timing and logging behaviors\nfunction trackProgress(logger: Logger) {\n let timestamp = Date.now();\n let summary: string;\n\n logger.info('Reading msgraph users and groups');\n\n function markReadComplete(read: { users: unknown[]; groups: unknown[] }) {\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 return { markCommitComplete };\n }\n\n function markCommitComplete() {\n const commitDuration = ((Date.now() - timestamp) / 1000).toFixed(1);\n logger.info(`Committed ${summary} in ${commitDuration} seconds.`);\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","/*\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 { Config } from '@backstage/config';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n LocationSpec,\n processingResult,\n} from '@backstage/plugin-catalog-backend';\nimport { Logger } from 'winston';\nimport {\n GroupTransformer,\n MicrosoftGraphClient,\n MicrosoftGraphProviderConfig,\n OrganizationTransformer,\n readMicrosoftGraphConfig,\n readMicrosoftGraphOrg,\n UserTransformer,\n} from '../microsoftGraph';\n\n/**\n * Extracts teams and users out of the Microsoft Graph API.\n *\n * @public\n * @deprecated Use the MicrosoftGraphOrgEntityProvider instead.\n */\nexport class MicrosoftGraphOrgReaderProcessor implements CatalogProcessor {\n private readonly providers: MicrosoftGraphProviderConfig[];\n private readonly logger: Logger;\n private readonly userTransformer?: UserTransformer;\n private readonly groupTransformer?: GroupTransformer;\n private readonly organizationTransformer?: OrganizationTransformer;\n\n static fromConfig(\n config: Config,\n options: {\n logger: Logger;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n },\n ) {\n const c = config.getOptionalConfig('catalog.processors.microsoftGraphOrg');\n return new MicrosoftGraphOrgReaderProcessor({\n ...options,\n providers: c ? readMicrosoftGraphConfig(c) : [],\n });\n }\n\n constructor(options: {\n providers: MicrosoftGraphProviderConfig[];\n logger: Logger;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n }) {\n options.logger.warn(\n 'MicrosoftGraphOrgReaderProcessor is deprecated. Please use MicrosoftGraphOrgEntityProvider instead. More info at https://github.com/backstage/backstage/blob/master/.changeset/long-bananas-rescue.md',\n );\n this.providers = options.providers;\n this.logger = options.logger;\n this.userTransformer = options.userTransformer;\n this.groupTransformer = options.groupTransformer;\n this.organizationTransformer = options.organizationTransformer;\n }\n\n getProcessorName(): string {\n return 'MicrosoftGraphOrgReaderProcessor';\n }\n\n async readLocation(\n location: LocationSpec,\n _optional: boolean,\n emit: CatalogProcessorEmit,\n ): Promise<boolean> {\n if (location.type !== 'microsoft-graph-org') {\n return false;\n }\n\n const provider = this.providers.find(p =>\n location.target.startsWith(p.target),\n );\n if (!provider) {\n throw new Error(\n `There is no Microsoft Graph Org provider that matches ${location.target}. Please add a configuration entry for it under catalog.processors.microsoftGraphOrg.providers.`,\n );\n }\n\n // Read out all the raw data\n const startTimestamp = Date.now();\n this.logger.info('Reading Microsoft Graph users and groups');\n\n // We create a client each time as we need one that matches the specific provider\n const client = MicrosoftGraphClient.create(provider);\n const { users, groups } = await readMicrosoftGraphOrg(\n client,\n provider.tenantId,\n {\n userExpand: provider.userExpand,\n userFilter: provider.userFilter,\n userGroupMemberFilter: provider.userGroupMemberFilter,\n userGroupMemberSearch: provider.userGroupMemberSearch,\n groupExpand: provider.groupExpand,\n groupFilter: provider.groupFilter,\n groupSearch: provider.groupSearch,\n groupSelect: provider.groupSelect,\n queryMode: provider.queryMode,\n userTransformer: this.userTransformer,\n groupTransformer: this.groupTransformer,\n organizationTransformer: this.organizationTransformer,\n logger: this.logger,\n },\n );\n\n const duration = ((Date.now() - startTimestamp) / 1000).toFixed(1);\n this.logger.debug(\n `Read ${users.length} users and ${groups.length} groups from Microsoft Graph in ${duration} seconds`,\n );\n\n // Done!\n for (const group of groups) {\n emit(processingResult.entity(location, group));\n }\n for (const user of users) {\n emit(processingResult.entity(location, user));\n }\n\n return true;\n }\n}\n"],"names":["ClientSecretCredential","DefaultAzureCredential","qs","fetch","trimEnd","limiterFactory","stringifyEntityRef","uuid","merge","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION","processingResult"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/microsoftGraph/client.ts","../src/microsoftGraph/config.ts","../src/microsoftGraph/constants.ts","../src/microsoftGraph/helper.ts","../src/microsoftGraph/org.ts","../src/microsoftGraph/read.ts","../src/processors/MicrosoftGraphOrgEntityProvider.ts","../src/processors/MicrosoftGraphOrgReaderProcessor.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 fetch, { Response } from 'node-fetch';\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\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.user' })\n | (MicrosoftGraph.User & { '@odata.type': '#microsoft.graph.group' });\n\n/**\n * A HTTP Client that communicates with Microsoft Graph API.\n * Simplify Authentication and API calls to get `User` and `Group` from Azure Active Directory\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 constructor(\n private readonly baseUrl: string,\n private readonly 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 },\n {\n addQueryPrefix: true,\n // Microsoft Graph doesn't like an encoded query string\n encode: false,\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 ): Promise<Response> {\n // Make sure that we always have a valid access token (might be cached)\n const token = await this.tokenCredential.getToken(\n 'https://graph.microsoft.com/.default',\n );\n\n if (!token) {\n throw new Error('Failed to obtain token from Azure Identity');\n }\n\n return await fetch(url, {\n headers: {\n ...headers,\n Authorization: `Bearer ${token.token}`,\n },\n });\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User}\n * from Graph API\n *\n * @public\n * @param userId - The unique identifier for the `User` resource\n * @param query - OData Query {@link ODataQuery}\n *\n */\n async getUserProfile(\n userId: string,\n query?: ODataQuery,\n ): Promise<MicrosoftGraph.User> {\n const response = await this.requestApi(`users/${userId}`, query);\n\n if (response.status !== 200) {\n await this.handleError('user profile', 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 * 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 */\n async *getUsers(\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n ): AsyncIterable<MicrosoftGraph.User> {\n yield* this.requestCollection<MicrosoftGraph.User>(\n `users`,\n query,\n queryMode,\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 */\n async *getGroups(\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n ): AsyncIterable<MicrosoftGraph.Group> {\n yield* this.requestCollection<MicrosoftGraph.Group>(\n `groups`,\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 *\n */\n async *getGroupMembers(groupId: string): AsyncIterable<GroupMember> {\n yield* this.requestCollection<GroupMember>(`groups/${groupId}/members`);\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 {@link entityName | 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","/*\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 { Config } from '@backstage/config';\nimport { trimEnd } from 'lodash';\n\nconst DEFAULT_PROVIDER_ID = 'default';\nconst DEFAULT_TARGET = 'https://graph.microsoft.com/v1.0';\n\n/**\n * The configuration parameters for a single Microsoft Graph provider.\n *\n * @public\n */\nexport type MicrosoftGraphProviderConfig = {\n /**\n * Identifier of the provider which will be used i.e. at the location key for ingested entities.\n */\n id: string;\n\n /**\n * The prefix of the target that this matches on, e.g.\n * \"https://graph.microsoft.com/v1.0\", with no trailing slash.\n */\n target: string;\n /**\n * The auth authority used.\n *\n * E.g. \"https://login.microsoftonline.com\"\n */\n authority?: string;\n /**\n * The tenant whose org data we are interested in.\n */\n tenantId: string;\n /**\n * The OAuth client ID to use for authenticating requests.\n * If specified, ClientSecret must also be specified\n */\n clientId?: string;\n /**\n * The OAuth client secret to use for authenticating requests.\n * If specified, ClientId must also be specified\n */\n clientSecret?: string;\n /**\n * The filter to apply to extract users.\n *\n * E.g. \"accountEnabled eq true and userType eq 'member'\"\n */\n userFilter?: string;\n /**\n * The \"expand\" argument to apply to users.\n *\n * E.g. \"manager\".\n */\n userExpand?: string;\n /**\n * The filter to apply to extract users by groups memberships.\n *\n * E.g. \"displayName eq 'Backstage Users'\"\n */\n userGroupMemberFilter?: string;\n /**\n * The search criteria to apply to extract users by groups memberships.\n *\n * E.g. \"\\\"displayName:-team\\\"\" would only match groups which contain '-team'\n */\n userGroupMemberSearch?: string;\n /**\n * The \"expand\" argument to apply to groups.\n *\n * E.g. \"member\".\n */\n groupExpand?: string;\n /**\n * The filter to apply to extract groups.\n *\n * E.g. \"securityEnabled eq false and mailEnabled eq true\"\n */\n groupFilter?: string;\n /**\n * The search criteria to apply to extract groups.\n *\n * E.g. \"\\\"displayName:-team\\\"\" would only match groups which contain '-team'\n */\n groupSearch?: string;\n\n /**\n * The fields to be fetched on query.\n *\n * E.g. [\"id\", \"displayName\", \"description\"]\n */\n groupSelect?: string[];\n\n /**\n * By default, the Microsoft Graph API only provides the basic feature set\n * for querying. Certain features are limited to advanced query capabilities\n * (see https://docs.microsoft.com/en-us/graph/aad-advanced-queries)\n * and need to be enabled.\n *\n * Some features like `$expand` are not available for advanced queries, though.\n */\n queryMode?: 'basic' | 'advanced';\n};\n\n/**\n * Parses configuration.\n *\n * @param config - The root of the msgraph config hierarchy\n *\n * @public\n * @deprecated Replaced by not exported `readProviderConfigs` and kept for backwards compatibility only.\n */\nexport function readMicrosoftGraphConfig(\n config: Config,\n): MicrosoftGraphProviderConfig[] {\n const providers: MicrosoftGraphProviderConfig[] = [];\n const providerConfigs = config.getOptionalConfigArray('providers') ?? [];\n\n for (const providerConfig of providerConfigs) {\n const target = trimEnd(\n providerConfig.getOptionalString('target') ?? DEFAULT_TARGET,\n '/',\n );\n const authority = providerConfig.getOptionalString('authority');\n\n const tenantId = providerConfig.getString('tenantId');\n const clientId = providerConfig.getOptionalString('clientId');\n const clientSecret = providerConfig.getOptionalString('clientSecret');\n\n const userExpand = providerConfig.getOptionalString('userExpand');\n const userFilter = providerConfig.getOptionalString('userFilter');\n const userGroupMemberFilter = providerConfig.getOptionalString(\n 'userGroupMemberFilter',\n );\n const userGroupMemberSearch = providerConfig.getOptionalString(\n 'userGroupMemberSearch',\n );\n const groupExpand = providerConfig.getOptionalString('groupExpand');\n const groupFilter = providerConfig.getOptionalString('groupFilter');\n const groupSearch = providerConfig.getOptionalString('groupSearch');\n\n if (userFilter && userGroupMemberFilter) {\n throw new Error(\n `userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.`,\n );\n }\n if (userFilter && userGroupMemberSearch) {\n throw new Error(\n `userGroupMemberSearch cannot be specified when userFilter is defined.`,\n );\n }\n\n const groupSelect = providerConfig.getOptionalStringArray('groupSelect');\n const queryMode = providerConfig.getOptionalString('queryMode');\n if (\n queryMode !== undefined &&\n queryMode !== 'basic' &&\n queryMode !== 'advanced'\n ) {\n throw new Error(`queryMode must be one of: basic, advanced`);\n }\n\n if (clientId && !clientSecret) {\n throw new Error(\n `clientSecret must be provided when clientId is defined.`,\n );\n }\n\n if (clientSecret && !clientId) {\n throw new Error(\n `clientId must be provided when clientSecret is defined.`,\n );\n }\n\n providers.push({\n id: target,\n target,\n authority,\n tenantId,\n clientId,\n clientSecret,\n userExpand,\n userFilter,\n userGroupMemberFilter,\n userGroupMemberSearch,\n groupExpand,\n groupFilter,\n groupSearch,\n groupSelect,\n queryMode,\n });\n }\n\n return providers;\n}\n\nexport function readProviderConfigs(\n config: Config,\n): MicrosoftGraphProviderConfig[] {\n const providersConfig = config.getOptionalConfig(\n 'catalog.providers.microsoftGraphOrg',\n );\n if (!providersConfig) {\n return [];\n }\n\n if (providersConfig.has('clientId')) {\n // simple/single config variant\n return [readProviderConfig(DEFAULT_PROVIDER_ID, providersConfig)];\n }\n\n return providersConfig.keys().map(id => {\n const providerConfig = providersConfig.getConfig(id);\n\n return readProviderConfig(id, providerConfig);\n });\n}\n\nexport function readProviderConfig(\n id: string,\n config: Config,\n): MicrosoftGraphProviderConfig {\n const target = trimEnd(\n config.getOptionalString('target') ?? DEFAULT_TARGET,\n '/',\n );\n const authority = config.getOptionalString('authority');\n\n const tenantId = config.getString('tenantId');\n const clientId = config.getOptionalString('clientId');\n const clientSecret = config.getOptionalString('clientSecret');\n\n const userExpand = config.getOptionalString('user.expand');\n const userFilter = config.getOptionalString('user.filter');\n\n const groupExpand = config.getOptionalString('group.expand');\n const groupFilter = config.getOptionalString('group.filter');\n const groupSearch = config.getOptionalString('group.search');\n const groupSelect = config.getOptionalStringArray('group.select');\n\n const userGroupMemberFilter = config.getOptionalString(\n 'userGroupMember.filter',\n );\n const userGroupMemberSearch = config.getOptionalString(\n 'userGroupMember.search',\n );\n\n if (userFilter && userGroupMemberFilter) {\n throw new Error(\n `userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.`,\n );\n }\n if (userFilter && userGroupMemberSearch) {\n throw new Error(\n `userGroupMemberSearch cannot be specified when userFilter is defined.`,\n );\n }\n\n if (clientId && !clientSecret) {\n throw new Error(`clientSecret must be provided when clientId is defined.`);\n }\n\n if (clientSecret && !clientId) {\n throw new Error(`clientId must be provided when clientSecret is defined.`);\n }\n\n return {\n id,\n target,\n authority,\n clientId,\n clientSecret,\n tenantId,\n userExpand,\n userFilter,\n groupExpand,\n groupFilter,\n groupSearch,\n groupSelect,\n userGroupMemberFilter,\n userGroupMemberSearch,\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The (primary) user email. Also used by the Microsoft auth provider to resolve the User entity.\n *\n * @public\n */\nexport const MICROSOFT_EMAIL_ANNOTATION = 'microsoft.com/email';\n\n/**\n * The tenant id used by the Microsoft Graph API\n *\n * @public\n */\nexport const MICROSOFT_GRAPH_TENANT_ID_ANNOTATION =\n 'graph.microsoft.com/tenant-id';\n\n/**\n * The group id used by the Microsoft Graph API\n *\n * @public\n */\nexport const MICROSOFT_GRAPH_GROUP_ID_ANNOTATION =\n 'graph.microsoft.com/group-id';\n\n/**\n * The user id used by the Microsoft Graph API\n *\n * @public\n */\nexport const MICROSOFT_GRAPH_USER_ID_ANNOTATION = 'graph.microsoft.com/user-id';\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Takes an input string and cleans it up to become suitable as an entity name.\n *\n * @public\n */\nexport function normalizeEntityName(name: string): string {\n let cleaned = name\n .trim()\n .toLocaleLowerCase()\n .replace(/[^a-zA-Z0-9_\\-\\.]/g, '_');\n\n // invalid to end with _\n while (cleaned.endsWith('_')) {\n cleaned = cleaned.substring(0, cleaned.length - 1);\n }\n\n // cleans up format for groups like 'my group (Reader)'\n while (cleaned.includes('__')) {\n // replaceAll from node.js >= 15\n cleaned = cleaned.replace('__', '_');\n }\n\n return cleaned;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { GroupEntity, UserEntity } from '@backstage/catalog-model';\n\n// TODO: Copied from plugin-catalog-backend, but we could also export them from\n// there. Or move them to catalog-model.\n\nexport function buildOrgHierarchy(groups: GroupEntity[]) {\n const groupsByName = new Map(groups.map(g => [g.metadata.name, g]));\n\n //\n // Make sure that g.parent.children contain g\n //\n\n for (const group of groups) {\n const selfName = group.metadata.name;\n const parentName = group.spec.parent;\n if (parentName) {\n const parent = groupsByName.get(parentName);\n if (parent && !parent.spec.children.includes(selfName)) {\n parent.spec.children.push(selfName);\n }\n }\n }\n\n //\n // Make sure that g.children.parent is g\n //\n\n for (const group of groups) {\n const selfName = group.metadata.name;\n for (const childName of group.spec.children) {\n const child = groupsByName.get(childName);\n if (child && !child.spec.parent) {\n child.spec.parent = selfName;\n }\n }\n }\n}\n\n// Ensure that users have their transitive group memberships. Requires that\n// the groups were previously processed with buildOrgHierarchy()\nexport function buildMemberOf(groups: GroupEntity[], users: UserEntity[]) {\n const groupsByName = new Map(groups.map(g => [g.metadata.name, g]));\n\n users.forEach(user => {\n const transitiveMemberOf = new Set<string>();\n\n const todo = [\n ...(user.spec.memberOf ?? []),\n ...groups\n .filter(g => g.spec.members?.includes(user.metadata.name))\n .map(g => g.metadata.name),\n ];\n\n for (;;) {\n const current = todo.pop();\n if (!current) {\n break;\n }\n\n if (!transitiveMemberOf.has(current)) {\n transitiveMemberOf.add(current);\n const group = groupsByName.get(current);\n if (group?.spec.parent) {\n todo.push(group.spec.parent);\n }\n }\n }\n\n user.spec.memberOf = [...transitiveMemberOf];\n });\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n GroupEntity,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport * as MicrosoftGraph from '@microsoft/microsoft-graph-types';\nimport limiterFactory from 'p-limit';\nimport { Logger } from 'winston';\nimport { MicrosoftGraphClient } from './client';\nimport {\n MICROSOFT_EMAIL_ANNOTATION,\n MICROSOFT_GRAPH_GROUP_ID_ANNOTATION,\n MICROSOFT_GRAPH_TENANT_ID_ANNOTATION,\n MICROSOFT_GRAPH_USER_ID_ANNOTATION,\n} from './constants';\nimport { normalizeEntityName } from './helper';\nimport { buildMemberOf, buildOrgHierarchy } from './org';\nimport {\n GroupTransformer,\n OrganizationTransformer,\n UserTransformer,\n} from './types';\n\n/**\n * The default implementation of the transformation from a graph user entry to\n * a User entity.\n *\n * @public\n */\nexport async function defaultUserTransformer(\n user: MicrosoftGraph.User,\n userPhoto?: string,\n): Promise<UserEntity | undefined> {\n if (!user.id || !user.displayName || !user.mail) {\n return undefined;\n }\n\n const name = normalizeEntityName(user.mail);\n const entity: UserEntity = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'User',\n metadata: {\n name,\n annotations: {\n [MICROSOFT_EMAIL_ANNOTATION]: user.mail!,\n [MICROSOFT_GRAPH_USER_ID_ANNOTATION]: user.id!,\n },\n },\n spec: {\n profile: {\n displayName: user.displayName!,\n email: user.mail!,\n\n // TODO: Additional fields?\n // jobTitle: user.jobTitle || undefined,\n // officeLocation: user.officeLocation || undefined,\n // mobilePhone: user.mobilePhone || undefined,\n },\n memberOf: [],\n },\n };\n\n if (userPhoto) {\n entity.spec.profile!.picture = userPhoto;\n }\n\n return entity;\n}\n\nexport async function readMicrosoftGraphUsers(\n client: MicrosoftGraphClient,\n options: {\n queryMode?: 'basic' | 'advanced';\n userFilter?: string;\n userExpand?: string;\n transformer?: UserTransformer;\n logger: Logger;\n },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n}> {\n const users: UserEntity[] = [];\n const limiter = limiterFactory(10);\n\n const transformer = options.transformer ?? defaultUserTransformer;\n const promises: Promise<void>[] = [];\n\n for await (const user of client.getUsers(\n {\n filter: options.userFilter,\n expand: options.userExpand,\n },\n options.queryMode,\n )) {\n // Process all users in parallel, otherwise it can take quite some time\n promises.push(\n limiter(async () => {\n let userPhoto;\n try {\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 } catch (e) {\n options.logger.warn(`Unable to load photo for ${user.id}`);\n }\n\n const entity = await transformer(user, userPhoto);\n\n if (!entity) {\n return;\n }\n\n users.push(entity);\n }),\n );\n }\n\n // Wait for all users and photos to be downloaded\n await Promise.all(promises);\n\n return { users };\n}\n\nexport async function readMicrosoftGraphUsersInGroups(\n client: MicrosoftGraphClient,\n options: {\n queryMode?: 'basic' | 'advanced';\n userExpand?: string;\n userGroupMemberSearch?: string;\n userGroupMemberFilter?: string;\n groupExpand?: string;\n transformer?: UserTransformer;\n logger: Logger;\n },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n}> {\n const users: UserEntity[] = [];\n\n const limiter = limiterFactory(10);\n\n const transformer = options.transformer ?? defaultUserTransformer;\n const userGroupMemberPromises: Promise<void>[] = [];\n const userPromises: Promise<void>[] = [];\n\n const groupMemberUsers: Set<string> = new Set();\n\n for await (const group of client.getGroups(\n {\n expand: options.groupExpand,\n search: options.userGroupMemberSearch,\n filter: options.userGroupMemberFilter,\n },\n options.queryMode,\n )) {\n // Process all groups in parallel, otherwise it can take quite some time\n userGroupMemberPromises.push(\n limiter(async () => {\n for await (const member of client.getGroupMembers(group.id!)) {\n if (!member.id) {\n continue;\n }\n\n if (member['@odata.type'] === '#microsoft.graph.user') {\n groupMemberUsers.add(member.id);\n }\n }\n }),\n );\n }\n\n // Wait for all group members\n await Promise.all(userGroupMemberPromises);\n\n options.logger.info(`groupMemberUsers ${groupMemberUsers.size}`);\n for (const userId of groupMemberUsers) {\n // Process all users in parallel, otherwise it can take quite some time\n userPromises.push(\n limiter(async () => {\n let user;\n let userPhoto;\n try {\n user = await client.getUserProfile(userId, {\n expand: options.userExpand,\n });\n } catch (e) {\n options.logger.warn(`Unable to load user for ${userId}`);\n }\n if (user) {\n try {\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 } catch (e) {\n options.logger.warn(`Unable to load userphoto for ${userId}`);\n }\n\n const entity = await transformer(user, userPhoto);\n\n if (!entity) {\n return;\n }\n users.push(entity);\n }\n }),\n );\n }\n\n // Wait for all users and photos to be downloaded\n await Promise.all(userPromises);\n\n return { users };\n}\n\n/**\n * The default implementation of the transformation from a graph organization\n * entry to a Group entity.\n *\n * @public\n */\nexport async function defaultOrganizationTransformer(\n organization: MicrosoftGraph.Organization,\n): Promise<GroupEntity | undefined> {\n if (!organization.id || !organization.displayName) {\n return undefined;\n }\n\n const name = normalizeEntityName(organization.displayName!);\n return {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Group',\n metadata: {\n name: name,\n description: organization.displayName!,\n annotations: {\n [MICROSOFT_GRAPH_TENANT_ID_ANNOTATION]: organization.id!,\n },\n },\n spec: {\n type: 'root',\n profile: {\n displayName: organization.displayName!,\n },\n children: [],\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\nfunction extractGroupName(group: MicrosoftGraph.Group): string {\n if (group.securityEnabled) {\n return group.displayName as string;\n }\n return (group.mailNickname || group.displayName) as string;\n}\n\n/**\n * The default implementation of the transformation from a graph group entry to\n * a Group entity.\n *\n * @public\n */\nexport async function defaultGroupTransformer(\n group: MicrosoftGraph.Group,\n groupPhoto?: string,\n): Promise<GroupEntity | undefined> {\n if (!group.id || !group.displayName) {\n return undefined;\n }\n\n const name = normalizeEntityName(extractGroupName(group));\n const entity: GroupEntity = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Group',\n metadata: {\n name: name,\n annotations: {\n [MICROSOFT_GRAPH_GROUP_ID_ANNOTATION]: group.id,\n },\n },\n spec: {\n type: 'team',\n profile: {},\n children: [],\n },\n };\n\n if (group.description) {\n entity.metadata.description = group.description;\n }\n if (group.displayName) {\n entity.spec.profile!.displayName = group.displayName;\n }\n if (group.mail) {\n entity.spec.profile!.email = group.mail;\n }\n if (groupPhoto) {\n entity.spec.profile!.picture = groupPhoto;\n }\n\n return entity;\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 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 search: options?.groupSearch,\n filter: options?.groupFilter,\n select: options?.groupSelect,\n },\n options?.queryMode,\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 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 }\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 the 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 retrieveItems(parentGroups, id).forEach(p => {\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 userGroupMemberSearch?: string;\n userGroupMemberFilter?: string;\n groupExpand?: string;\n groupSearch?: string;\n groupFilter?: string;\n groupSelect?: string[];\n queryMode?: 'basic' | 'advanced';\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n logger: Logger;\n },\n): Promise<{ users: UserEntity[]; groups: GroupEntity[] }> {\n const users: UserEntity[] = [];\n\n if (options.userGroupMemberFilter || options.userGroupMemberSearch) {\n const { users: usersInGroups } = await readMicrosoftGraphUsersInGroups(\n client,\n {\n queryMode: options.queryMode,\n userGroupMemberFilter: options.userGroupMemberFilter,\n userGroupMemberSearch: options.userGroupMemberSearch,\n transformer: options.userTransformer,\n logger: options.logger,\n },\n );\n users.push(...usersInGroups);\n } else {\n const { users: usersWithFilter } = await readMicrosoftGraphUsers(client, {\n queryMode: options.queryMode,\n userFilter: options.userFilter,\n userExpand: options.userExpand,\n transformer: options.userTransformer,\n logger: options.logger,\n });\n users.push(...usersWithFilter);\n }\n const { groups, rootGroup, groupMember, groupMemberOf } =\n await readMicrosoftGraphGroups(client, tenantId, {\n queryMode: options.queryMode,\n groupSearch: options.groupSearch,\n groupFilter: options.groupFilter,\n groupSelect: options.groupSelect,\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\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 target.get(key) ?? new Set();\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TaskRunner } from '@backstage/backend-tasks';\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-backend';\nimport { merge } from 'lodash';\nimport * as uuid from 'uuid';\nimport { Logger } from 'winston';\nimport {\n GroupTransformer,\n MicrosoftGraphClient,\n MicrosoftGraphProviderConfig,\n MICROSOFT_GRAPH_GROUP_ID_ANNOTATION,\n MICROSOFT_GRAPH_TENANT_ID_ANNOTATION,\n MICROSOFT_GRAPH_USER_ID_ANNOTATION,\n OrganizationTransformer,\n readMicrosoftGraphConfig,\n readMicrosoftGraphOrg,\n UserTransformer,\n} from '../microsoftGraph';\nimport { readProviderConfigs } from '../microsoftGraph/config';\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: Logger;\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-tasks#PluginTaskScheduler.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule: 'manual' | TaskRunner;\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/**\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: Logger;\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-tasks#PluginTaskScheduler.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule: 'manual' | TaskRunner;\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/**\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 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 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 });\n provider.schedule(options.schedule);\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 logger,\n provider,\n });\n\n result.schedule(options.schedule);\n\n return result;\n }\n\n constructor(\n private options: {\n id: string;\n provider: MicrosoftGraphProviderConfig;\n logger: Logger;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n },\n ) {}\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getProviderName} */\n getProviderName() {\n return `MicrosoftGraphOrgEntityProvider:${this.options.id}`;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#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?: Logger }) {\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.provider;\n const { markReadComplete } = trackProgress(logger);\n const client = MicrosoftGraphClient.create(this.options.provider);\n const { users, groups } = await readMicrosoftGraphOrg(\n client,\n provider.tenantId,\n {\n userFilter: provider.userFilter,\n userGroupMemberFilter: provider.userGroupMemberFilter,\n userGroupMemberSearch: provider.userGroupMemberSearch,\n groupFilter: provider.groupFilter,\n groupSearch: provider.groupSearch,\n groupSelect: provider.groupSelect,\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({ users, groups });\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();\n }\n\n private schedule(\n schedule: MicrosoftGraphOrgEntityProviderOptions['schedule'],\n ) {\n if (schedule === 'manual') {\n return;\n }\n\n this.scheduleFn = async () => {\n const id = `${this.getProviderName()}:refresh`;\n await schedule.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(error);\n }\n },\n });\n };\n }\n}\n\n// Helps wrap the timing and logging behaviors\nfunction trackProgress(logger: Logger) {\n let timestamp = Date.now();\n let summary: string;\n\n logger.info('Reading msgraph users and groups');\n\n function markReadComplete(read: { users: unknown[]; groups: unknown[] }) {\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 return { markCommitComplete };\n }\n\n function markCommitComplete() {\n const commitDuration = ((Date.now() - timestamp) / 1000).toFixed(1);\n logger.info(`Committed ${summary} in ${commitDuration} seconds.`);\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","/*\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 { Config } from '@backstage/config';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n LocationSpec,\n processingResult,\n} from '@backstage/plugin-catalog-backend';\nimport { Logger } from 'winston';\nimport {\n GroupTransformer,\n MicrosoftGraphClient,\n MicrosoftGraphProviderConfig,\n OrganizationTransformer,\n readMicrosoftGraphConfig,\n readMicrosoftGraphOrg,\n UserTransformer,\n} from '../microsoftGraph';\n\n/**\n * Extracts teams and users out of the Microsoft Graph API.\n *\n * @public\n * @deprecated Use the MicrosoftGraphOrgEntityProvider instead.\n */\nexport class MicrosoftGraphOrgReaderProcessor implements CatalogProcessor {\n private readonly providers: MicrosoftGraphProviderConfig[];\n private readonly logger: Logger;\n private readonly userTransformer?: UserTransformer;\n private readonly groupTransformer?: GroupTransformer;\n private readonly organizationTransformer?: OrganizationTransformer;\n\n static fromConfig(\n config: Config,\n options: {\n logger: Logger;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n },\n ) {\n const c = config.getOptionalConfig('catalog.processors.microsoftGraphOrg');\n return new MicrosoftGraphOrgReaderProcessor({\n ...options,\n providers: c ? readMicrosoftGraphConfig(c) : [],\n });\n }\n\n constructor(options: {\n providers: MicrosoftGraphProviderConfig[];\n logger: Logger;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n }) {\n options.logger.warn(\n 'MicrosoftGraphOrgReaderProcessor is deprecated. Please use MicrosoftGraphOrgEntityProvider instead. More info at https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-msgraph/CHANGELOG.md#040-next1',\n );\n this.providers = options.providers;\n this.logger = options.logger;\n this.userTransformer = options.userTransformer;\n this.groupTransformer = options.groupTransformer;\n this.organizationTransformer = options.organizationTransformer;\n }\n\n getProcessorName(): string {\n return 'MicrosoftGraphOrgReaderProcessor';\n }\n\n async readLocation(\n location: LocationSpec,\n _optional: boolean,\n emit: CatalogProcessorEmit,\n ): Promise<boolean> {\n if (location.type !== 'microsoft-graph-org') {\n return false;\n }\n\n const provider = this.providers.find(p =>\n location.target.startsWith(p.target),\n );\n if (!provider) {\n throw new Error(\n `There is no Microsoft Graph Org provider that matches ${location.target}. Please add a configuration entry for it under catalog.processors.microsoftGraphOrg.providers.`,\n );\n }\n\n // Read out all the raw data\n const startTimestamp = Date.now();\n this.logger.info('Reading Microsoft Graph users and groups');\n\n // We create a client each time as we need one that matches the specific provider\n const client = MicrosoftGraphClient.create(provider);\n const { users, groups } = await readMicrosoftGraphOrg(\n client,\n provider.tenantId,\n {\n userExpand: provider.userExpand,\n userFilter: provider.userFilter,\n userGroupMemberFilter: provider.userGroupMemberFilter,\n userGroupMemberSearch: provider.userGroupMemberSearch,\n groupExpand: provider.groupExpand,\n groupFilter: provider.groupFilter,\n groupSearch: provider.groupSearch,\n groupSelect: provider.groupSelect,\n queryMode: provider.queryMode,\n userTransformer: this.userTransformer,\n groupTransformer: this.groupTransformer,\n organizationTransformer: this.organizationTransformer,\n logger: this.logger,\n },\n );\n\n const duration = ((Date.now() - startTimestamp) / 1000).toFixed(1);\n this.logger.debug(\n `Read ${users.length} users and ${groups.length} groups from Microsoft Graph in ${duration} seconds`,\n );\n\n // Done!\n for (const group of groups) {\n emit(processingResult.entity(location, group));\n }\n for (const user of users) {\n emit(processingResult.entity(location, user));\n }\n\n return true;\n }\n}\n"],"names":["ClientSecretCredential","DefaultAzureCredential","qs","fetch","trimEnd","limiterFactory","stringifyEntityRef","uuid","merge","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION","processingResult"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMO,MAAM,oBAAoB,CAAC;AAClC,EAAE,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE;AACxC,IAAI,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;AAC3B,IAAI,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;AAC3C,GAAG;AACH,EAAE,OAAO,MAAM,CAAC,MAAM,EAAE;AACxB,IAAI,MAAM,OAAO,GAAG;AACpB,MAAM,aAAa,EAAE,MAAM,CAAC,SAAS;AACrC,MAAM,QAAQ,EAAE,MAAM,CAAC,QAAQ;AAC/B,KAAK,CAAC;AACN,IAAI,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,YAAY,GAAG,IAAIA,+BAAsB;AAC1F,MAAM,MAAM,CAAC,QAAQ;AACrB,MAAM,MAAM,CAAC,QAAQ;AACrB,MAAM,MAAM,CAAC,YAAY;AACzB,MAAM,OAAO;AACb,KAAK,GAAG,IAAIC,+BAAsB,CAAC,OAAO,CAAC,CAAC;AAC5C,IAAI,OAAO,IAAI,oBAAoB,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAC/D,GAAG;AACH,EAAE,OAAO,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE;AACnD,IAAI,MAAM,gBAAgB,GAAG,CAAC,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,UAAU,GAAG,SAAS,IAAI,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC;AAC5H,IAAI,IAAI,gBAAgB,KAAK,UAAU,KAAK,CAAC,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,MAAM,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE;AACjI,MAAM,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;AACzB,KAAK;AACL,IAAI,MAAM,OAAO,GAAG,gBAAgB,KAAK,UAAU,GAAG;AACtD,MAAM,gBAAgB,EAAE,UAAU;AAClC,KAAK,GAAG,EAAE,CAAC;AACX,IAAI,IAAI,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;AAC/D,IAAI,WAAW;AACf,MAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE;AACnC,QAAQ,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC/C,OAAO;AACP,MAAM,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;AAC3C,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC;AACpC,MAAM,OAAO,QAAQ,CAAC;AACtB,MAAM,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE;AACtC,QAAQ,OAAO;AACf,OAAO;AACP,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC;AAC3E,KAAK;AACL,GAAG;AACH,EAAE,MAAM,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE;AACzC,IAAI,IAAI,EAAE,CAAC;AACX,IAAI,MAAM,WAAW,GAAGC,sBAAE,CAAC,SAAS;AACpC,MAAM;AACN,QAAQ,OAAO,EAAE,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM;AACtD,QAAQ,OAAO,EAAE,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM;AACtD,QAAQ,OAAO,EAAE,CAAC,EAAE,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,KAAK,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;AAC7F,QAAQ,OAAO,EAAE,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM;AACtD,QAAQ,MAAM,EAAE,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK;AACpD,OAAO;AACP,MAAM;AACN,QAAQ,cAAc,EAAE,IAAI;AAC5B,QAAQ,MAAM,EAAE,KAAK;AACrB,OAAO;AACP,KAAK,CAAC;AACN,IAAI,OAAO,MAAM,IAAI,CAAC,UAAU;AAChC,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC;AAC7C,MAAM,OAAO;AACb,KAAK,CAAC;AACN,GAAG;AACH,EAAE,MAAM,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE;AACjC,IAAI,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ;AACrD,MAAM,sCAAsC;AAC5C,KAAK,CAAC;AACN,IAAI,IAAI,CAAC,KAAK,EAAE;AAChB,MAAM,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;AACpE,KAAK;AACL,IAAI,OAAO,MAAMC,yBAAK,CAAC,GAAG,EAAE;AAC5B,MAAM,OAAO,EAAE;AACf,QAAQ,GAAG,OAAO;AAClB,QAAQ,aAAa,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;AAC9C,OAAO;AACP,KAAK,CAAC,CAAC;AACP,GAAG;AACH,EAAE,MAAM,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE;AACtC,IAAI,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACrE,IAAI,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE;AACjC,MAAM,MAAM,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;AACvD,KAAK;AACL,IAAI,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;AACjC,GAAG;AACH,EAAE,MAAM,yBAAyB,CAAC,MAAM,EAAE,OAAO,EAAE;AACnD,IAAI,OAAO,MAAM,IAAI,CAAC,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AACtE,GAAG;AACH,EAAE,MAAM,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE;AACrC,IAAI,OAAO,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AACxD,GAAG;AACH,EAAE,OAAO,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE;AACpC,IAAI,OAAO,IAAI,CAAC,iBAAiB;AACjC,MAAM,CAAC,KAAK,CAAC;AACb,MAAM,KAAK;AACX,MAAM,SAAS;AACf,KAAK,CAAC;AACN,GAAG;AACH,EAAE,MAAM,0BAA0B,CAAC,OAAO,EAAE,OAAO,EAAE;AACrD,IAAI,OAAO,MAAM,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AACxE,GAAG;AACH,EAAE,MAAM,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE;AACvC,IAAI,OAAO,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAC1D,GAAG;AACH,EAAE,OAAO,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE;AACrC,IAAI,OAAO,IAAI,CAAC,iBAAiB;AACjC,MAAM,CAAC,MAAM,CAAC;AACd,MAAM,KAAK;AACX,MAAM,SAAS;AACf,KAAK,CAAC;AACN,GAAG;AACH,EAAE,OAAO,eAAe,CAAC,OAAO,EAAE;AAClC,IAAI,OAAO,IAAI,CAAC,iBAAiB,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC/D,GAAG;AACH,EAAE,MAAM,eAAe,CAAC,QAAQ,EAAE;AAClC,IAAI,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvE,IAAI,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE;AACjC,MAAM,MAAM,IAAI,CAAC,WAAW,CAAC,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AACnE,KAAK;AACL,IAAI,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;AACjC,GAAG;AACH,EAAE,MAAM,qBAAqB,CAAC,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE;AACvD,IAAI,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;AACzE,IAAI,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE;AACjC,MAAM,OAAO,KAAK,CAAC,CAAC;AACpB,KAAK,MAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE;AACxC,MAAM,MAAM,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAC/D,KAAK;AACL,IAAI,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzC,IAAI,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;AAChC,IAAI,IAAI,aAAa,GAAG,KAAK,CAAC,CAAC;AAC/B,IAAI,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE;AAC5B,MAAM,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,MAAM,IAAI,aAAa,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,IAAI,OAAO,EAAE;AACrF,QAAQ,aAAa,GAAG,CAAC,CAAC;AAC1B,OAAO;AACP,KAAK;AACL,IAAI,IAAI,CAAC,aAAa,EAAE;AACxB,MAAM,OAAO,KAAK,CAAC,CAAC;AACpB,KAAK;AACL,IAAI,OAAO,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC;AACjE,GAAG;AACH,EAAE,MAAM,QAAQ,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE;AACzC,IAAI,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC;AAC7G,IAAI,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AACjD,IAAI,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE;AACjC,MAAM,OAAO,KAAK,CAAC,CAAC;AACpB,KAAK,MAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE;AACxC,MAAM,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAChD,KAAK;AACL,IAAI,OAAO,CAAC,uBAAuB,EAAE,MAAM,CAAC,IAAI;AAChD,MAAM,MAAM,QAAQ,CAAC,WAAW,EAAE;AAClC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC3B,GAAG;AACH,EAAE,MAAM,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE;AACpC,IAAI,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzC,IAAI,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;AAC/B,IAAI,MAAM,IAAI,KAAK;AACnB,MAAM,CAAC,oBAAoB,EAAE,IAAI,CAAC,uBAAuB,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;AAC1F,KAAK,CAAC;AACN,GAAG;AACH;;ACjKA,MAAM,mBAAmB,GAAG,SAAS,CAAC;AACtC,MAAM,cAAc,GAAG,kCAAkC,CAAC;AACnD,SAAS,wBAAwB,CAAC,MAAM,EAAE;AACjD,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACb,EAAE,MAAM,SAAS,GAAG,EAAE,CAAC;AACvB,EAAE,MAAM,eAAe,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,sBAAsB,CAAC,WAAW,CAAC,KAAK,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC;AAC9F,EAAE,KAAK,MAAM,cAAc,IAAI,eAAe,EAAE;AAChD,IAAI,MAAM,MAAM,GAAGC,cAAO;AAC1B,MAAM,CAAC,EAAE,GAAG,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,KAAK,IAAI,GAAG,EAAE,GAAG,cAAc;AACrF,MAAM,GAAG;AACT,KAAK,CAAC;AACN,IAAI,MAAM,SAAS,GAAG,cAAc,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;AACpE,IAAI,MAAM,QAAQ,GAAG,cAAc,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AAC1D,IAAI,MAAM,QAAQ,GAAG,cAAc,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;AAClE,IAAI,MAAM,YAAY,GAAG,cAAc,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;AAC1E,IAAI,MAAM,UAAU,GAAG,cAAc,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;AACtE,IAAI,MAAM,UAAU,GAAG,cAAc,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;AACtE,IAAI,MAAM,qBAAqB,GAAG,cAAc,CAAC,iBAAiB;AAClE,MAAM,uBAAuB;AAC7B,KAAK,CAAC;AACN,IAAI,MAAM,qBAAqB,GAAG,cAAc,CAAC,iBAAiB;AAClE,MAAM,uBAAuB;AAC7B,KAAK,CAAC;AACN,IAAI,MAAM,WAAW,GAAG,cAAc,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;AACxE,IAAI,MAAM,WAAW,GAAG,cAAc,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;AACxE,IAAI,MAAM,WAAW,GAAG,cAAc,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;AACxE,IAAI,IAAI,UAAU,IAAI,qBAAqB,EAAE;AAC7C,MAAM,MAAM,IAAI,KAAK;AACrB,QAAQ,CAAC,uFAAuF,CAAC;AACjG,OAAO,CAAC;AACR,KAAK;AACL,IAAI,IAAI,UAAU,IAAI,qBAAqB,EAAE;AAC7C,MAAM,MAAM,IAAI,KAAK;AACrB,QAAQ,CAAC,qEAAqE,CAAC;AAC/E,OAAO,CAAC;AACR,KAAK;AACL,IAAI,MAAM,WAAW,GAAG,cAAc,CAAC,sBAAsB,CAAC,aAAa,CAAC,CAAC;AAC7E,IAAI,MAAM,SAAS,GAAG,cAAc,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;AACpE,IAAI,IAAI,SAAS,KAAK,KAAK,CAAC,IAAI,SAAS,KAAK,OAAO,IAAI,SAAS,KAAK,UAAU,EAAE;AACnF,MAAM,MAAM,IAAI,KAAK,CAAC,CAAC,yCAAyC,CAAC,CAAC,CAAC;AACnE,KAAK;AACL,IAAI,IAAI,QAAQ,IAAI,CAAC,YAAY,EAAE;AACnC,MAAM,MAAM,IAAI,KAAK;AACrB,QAAQ,CAAC,uDAAuD,CAAC;AACjE,OAAO,CAAC;AACR,KAAK;AACL,IAAI,IAAI,YAAY,IAAI,CAAC,QAAQ,EAAE;AACnC,MAAM,MAAM,IAAI,KAAK;AACrB,QAAQ,CAAC,uDAAuD,CAAC;AACjE,OAAO,CAAC;AACR,KAAK;AACL,IAAI,SAAS,CAAC,IAAI,CAAC;AACnB,MAAM,EAAE,EAAE,MAAM;AAChB,MAAM,MAAM;AACZ,MAAM,SAAS;AACf,MAAM,QAAQ;AACd,MAAM,QAAQ;AACd,MAAM,YAAY;AAClB,MAAM,UAAU;AAChB,MAAM,UAAU;AAChB,MAAM,qBAAqB;AAC3B,MAAM,qBAAqB;AAC3B,MAAM,WAAW;AACjB,MAAM,WAAW;AACjB,MAAM,WAAW;AACjB,MAAM,WAAW;AACjB,MAAM,SAAS;AACf,KAAK,CAAC,CAAC;AACP,GAAG;AACH,EAAE,OAAO,SAAS,CAAC;AACnB,CAAC;AACM,SAAS,mBAAmB,CAAC,MAAM,EAAE;AAC5C,EAAE,MAAM,eAAe,GAAG,MAAM,CAAC,iBAAiB;AAClD,IAAI,qCAAqC;AACzC,GAAG,CAAC;AACJ,EAAE,IAAI,CAAC,eAAe,EAAE;AACxB,IAAI,OAAO,EAAE,CAAC;AACd,GAAG;AACH,EAAE,IAAI,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE;AACvC,IAAI,OAAO,CAAC,kBAAkB,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC,CAAC;AACtE,GAAG;AACH,EAAE,OAAO,eAAe,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK;AAC5C,IAAI,MAAM,cAAc,GAAG,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;AACzD,IAAI,OAAO,kBAAkB,CAAC,EAAE,EAAE,cAAc,CAAC,CAAC;AAClD,GAAG,CAAC,CAAC;AACL,CAAC;AACM,SAAS,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE;AAC/C,EAAE,IAAI,EAAE,CAAC;AACT,EAAE,MAAM,MAAM,GAAGA,cAAO;AACxB,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,KAAK,IAAI,GAAG,EAAE,GAAG,cAAc;AAC3E,IAAI,GAAG;AACP,GAAG,CAAC;AACJ,EAAE,MAAM,SAAS,GAAG,MAAM,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;AAC1D,EAAE,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AAChD,EAAE,MAAM,QAAQ,GAAG,MAAM,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;AACxD,EAAE,MAAM,YAAY,GAAG,MAAM,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;AAChE,EAAE,MAAM,UAAU,GAAG,MAAM,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;AAC7D,EAAE,MAAM,UAAU,GAAG,MAAM,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;AAC7D,EAAE,MAAM,WAAW,GAAG,MAAM,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;AAC/D,EAAE,MAAM,WAAW,GAAG,MAAM,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;AAC/D,EAAE,MAAM,WAAW,GAAG,MAAM,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;AAC/D,EAAE,MAAM,WAAW,GAAG,MAAM,CAAC,sBAAsB,CAAC,cAAc,CAAC,CAAC;AACpE,EAAE,MAAM,qBAAqB,GAAG,MAAM,CAAC,iBAAiB;AACxD,IAAI,wBAAwB;AAC5B,GAAG,CAAC;AACJ,EAAE,MAAM,qBAAqB,GAAG,MAAM,CAAC,iBAAiB;AACxD,IAAI,wBAAwB;AAC5B,GAAG,CAAC;AACJ,EAAE,IAAI,UAAU,IAAI,qBAAqB,EAAE;AAC3C,IAAI,MAAM,IAAI,KAAK;AACnB,MAAM,CAAC,uFAAuF,CAAC;AAC/F,KAAK,CAAC;AACN,GAAG;AACH,EAAE,IAAI,UAAU,IAAI,qBAAqB,EAAE;AAC3C,IAAI,MAAM,IAAI,KAAK;AACnB,MAAM,CAAC,qEAAqE,CAAC;AAC7E,KAAK,CAAC;AACN,GAAG;AACH,EAAE,IAAI,QAAQ,IAAI,CAAC,YAAY,EAAE;AACjC,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,uDAAuD,CAAC,CAAC,CAAC;AAC/E,GAAG;AACH,EAAE,IAAI,YAAY,IAAI,CAAC,QAAQ,EAAE;AACjC,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,uDAAuD,CAAC,CAAC,CAAC;AAC/E,GAAG;AACH,EAAE,OAAO;AACT,IAAI,EAAE;AACN,IAAI,MAAM;AACV,IAAI,SAAS;AACb,IAAI,QAAQ;AACZ,IAAI,YAAY;AAChB,IAAI,QAAQ;AACZ,IAAI,UAAU;AACd,IAAI,UAAU;AACd,IAAI,WAAW;AACf,IAAI,WAAW;AACf,IAAI,WAAW;AACf,IAAI,WAAW;AACf,IAAI,qBAAqB;AACzB,IAAI,qBAAqB;AACzB,GAAG,CAAC;AACJ;;AC7IY,MAAC,0BAA0B,GAAG,sBAAsB;AACpD,MAAC,oCAAoC,GAAG,gCAAgC;AACxE,MAAC,mCAAmC,GAAG,+BAA+B;AACtE,MAAC,kCAAkC,GAAG;;ACH3C,SAAS,mBAAmB,CAAC,IAAI,EAAE;AAC1C,EAAE,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,iBAAiB,EAAE,CAAC,OAAO,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;AACnF,EAAE,OAAO,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AAChC,IAAI,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACvD,GAAG;AACH,EAAE,OAAO,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AACjC,IAAI,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACzC,GAAG;AACH,EAAE,OAAO,OAAO,CAAC;AACjB;;ACTO,SAAS,iBAAiB,CAAC,MAAM,EAAE;AAC1C,EAAE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACxE,EAAE,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;AAC9B,IAAI,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;AACzC,IAAI,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;AACzC,IAAI,IAAI,UAAU,EAAE;AACpB,MAAM,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AAClD,MAAM,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;AAC9D,QAAQ,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC5C,OAAO;AACP,KAAK;AACL,GAAG;AACH,EAAE,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;AAC9B,IAAI,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;AACzC,IAAI,KAAK,MAAM,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE;AACjD,MAAM,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAChD,MAAM,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE;AACvC,QAAQ,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC;AACrC,OAAO;AACP,KAAK;AACL,GAAG;AACH,CAAC;AACM,SAAS,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE;AAC7C,EAAE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACxE,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK;AAC1B,IAAI,IAAI,EAAE,CAAC;AACX,IAAI,MAAM,kBAAkB,mBAAmB,IAAI,GAAG,EAAE,CAAC;AACzD,IAAI,MAAM,IAAI,GAAG;AACjB,MAAM,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,IAAI,GAAG,EAAE,GAAG,EAAE;AACpD,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK;AAC9B,QAAQ,IAAI,GAAG,CAAC;AAChB,QAAQ,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,KAAK,IAAI,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC1F,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;AACpC,KAAK,CAAC;AACN,IAAI,WAAW;AACf,MAAM,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AACjC,MAAM,IAAI,CAAC,OAAO,EAAE;AACpB,QAAQ,MAAM;AACd,OAAO;AACP,MAAM,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;AAC5C,QAAQ,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACxC,QAAQ,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAChD,QAAQ,IAAI,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE;AACxD,UAAU,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACvC,SAAS;AACT,OAAO;AACP,KAAK;AACL,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,GAAG,kBAAkB,CAAC,CAAC;AACjD,GAAG,CAAC,CAAC;AACL;;ACrCO,eAAe,sBAAsB,CAAC,IAAI,EAAE,SAAS,EAAE;AAC9D,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;AACnD,IAAI,OAAO,KAAK,CAAC,CAAC;AAClB,GAAG;AACH,EAAE,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC9C,EAAE,MAAM,MAAM,GAAG;AACjB,IAAI,UAAU,EAAE,uBAAuB;AACvC,IAAI,IAAI,EAAE,MAAM;AAChB,IAAI,QAAQ,EAAE;AACd,MAAM,IAAI;AACV,MAAM,WAAW,EAAE;AACnB,QAAQ,CAAC,0BAA0B,GAAG,IAAI,CAAC,IAAI;AAC/C,QAAQ,CAAC,kCAAkC,GAAG,IAAI,CAAC,EAAE;AACrD,OAAO;AACP,KAAK;AACL,IAAI,IAAI,EAAE;AACV,MAAM,OAAO,EAAE;AACf,QAAQ,WAAW,EAAE,IAAI,CAAC,WAAW;AACrC,QAAQ,KAAK,EAAE,IAAI,CAAC,IAAI;AACxB,OAAO;AACP,MAAM,QAAQ,EAAE,EAAE;AAClB,KAAK;AACL,GAAG,CAAC;AACJ,EAAE,IAAI,SAAS,EAAE;AACjB,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;AAC5C,GAAG;AACH,EAAE,OAAO,MAAM,CAAC;AAChB,CAAC;AACM,eAAe,uBAAuB,CAAC,MAAM,EAAE,OAAO,EAAE;AAC/D,EAAE,IAAI,EAAE,CAAC;AACT,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;AACnB,EAAE,MAAM,OAAO,GAAGC,kCAAc,CAAC,EAAE,CAAC,CAAC;AACrC,EAAE,MAAM,WAAW,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,WAAW,KAAK,IAAI,GAAG,EAAE,GAAG,sBAAsB,CAAC;AACvF,EAAE,MAAM,QAAQ,GAAG,EAAE,CAAC;AACtB,EAAE,WAAW,MAAM,IAAI,IAAI,MAAM,CAAC,QAAQ;AAC1C,IAAI;AACJ,MAAM,MAAM,EAAE,OAAO,CAAC,UAAU;AAChC,MAAM,MAAM,EAAE,OAAO,CAAC,UAAU;AAChC,KAAK;AACL,IAAI,OAAO,CAAC,SAAS;AACrB,GAAG,EAAE;AACL,IAAI,QAAQ,CAAC,IAAI;AACjB,MAAM,OAAO,CAAC,YAAY;AAC1B,QAAQ,IAAI,SAAS,CAAC;AACtB,QAAQ,IAAI;AACZ,UAAU,SAAS,GAAG,MAAM,MAAM,CAAC,yBAAyB;AAC5D,YAAY,IAAI,CAAC,EAAE;AACnB,YAAY,GAAG;AACf,WAAW,CAAC;AACZ,SAAS,CAAC,OAAO,CAAC,EAAE;AACpB,UAAU,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,yBAAyB,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACrE,SAAS;AACT,QAAQ,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AAC1D,QAAQ,IAAI,CAAC,MAAM,EAAE;AACrB,UAAU,OAAO;AACjB,SAAS;AACT,QAAQ,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC3B,OAAO,CAAC;AACR,KAAK,CAAC;AACN,GAAG;AACH,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC9B,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC;AACM,eAAe,+BAA+B,CAAC,MAAM,EAAE,OAAO,EAAE;AACvE,EAAE,IAAI,EAAE,CAAC;AACT,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;AACnB,EAAE,MAAM,OAAO,GAAGA,kCAAc,CAAC,EAAE,CAAC,CAAC;AACrC,EAAE,MAAM,WAAW,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,WAAW,KAAK,IAAI,GAAG,EAAE,GAAG,sBAAsB,CAAC;AACvF,EAAE,MAAM,uBAAuB,GAAG,EAAE,CAAC;AACrC,EAAE,MAAM,YAAY,GAAG,EAAE,CAAC;AAC1B,EAAE,MAAM,gBAAgB,mBAAmB,IAAI,GAAG,EAAE,CAAC;AACrD,EAAE,WAAW,MAAM,KAAK,IAAI,MAAM,CAAC,SAAS;AAC5C,IAAI;AACJ,MAAM,MAAM,EAAE,OAAO,CAAC,WAAW;AACjC,MAAM,MAAM,EAAE,OAAO,CAAC,qBAAqB;AAC3C,MAAM,MAAM,EAAE,OAAO,CAAC,qBAAqB;AAC3C,KAAK;AACL,IAAI,OAAO,CAAC,SAAS;AACrB,GAAG,EAAE;AACL,IAAI,uBAAuB,CAAC,IAAI;AAChC,MAAM,OAAO,CAAC,YAAY;AAC1B,QAAQ,WAAW,MAAM,MAAM,IAAI,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACrE,UAAU,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE;AAC1B,YAAY,SAAS;AACrB,WAAW;AACX,UAAU,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,uBAAuB,EAAE;AACjE,YAAY,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAC5C,WAAW;AACX,SAAS;AACT,OAAO,CAAC;AACR,KAAK,CAAC;AACN,GAAG;AACH,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;AAC7C,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACnE,EAAE,KAAK,MAAM,MAAM,IAAI,gBAAgB,EAAE;AACzC,IAAI,YAAY,CAAC,IAAI;AACrB,MAAM,OAAO,CAAC,YAAY;AAC1B,QAAQ,IAAI,IAAI,CAAC;AACjB,QAAQ,IAAI,SAAS,CAAC;AACtB,QAAQ,IAAI;AACZ,UAAU,IAAI,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE;AACrD,YAAY,MAAM,EAAE,OAAO,CAAC,UAAU;AACtC,WAAW,CAAC,CAAC;AACb,SAAS,CAAC,OAAO,CAAC,EAAE;AACpB,UAAU,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AACnE,SAAS;AACT,QAAQ,IAAI,IAAI,EAAE;AAClB,UAAU,IAAI;AACd,YAAY,SAAS,GAAG,MAAM,MAAM,CAAC,yBAAyB;AAC9D,cAAc,IAAI,CAAC,EAAE;AACrB,cAAc,GAAG;AACjB,aAAa,CAAC;AACd,WAAW,CAAC,OAAO,CAAC,EAAE;AACtB,YAAY,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AAC1E,WAAW;AACX,UAAU,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AAC5D,UAAU,IAAI,CAAC,MAAM,EAAE;AACvB,YAAY,OAAO;AACnB,WAAW;AACX,UAAU,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC7B,SAAS;AACT,OAAO,CAAC;AACR,KAAK,CAAC;AACN,GAAG;AACH,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;AAClC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC;AACM,eAAe,8BAA8B,CAAC,YAAY,EAAE;AACnE,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE;AACrD,IAAI,OAAO,KAAK,CAAC,CAAC;AAClB,GAAG;AACH,EAAE,MAAM,IAAI,GAAG,mBAAmB,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;AAC7D,EAAE,OAAO;AACT,IAAI,UAAU,EAAE,uBAAuB;AACvC,IAAI,IAAI,EAAE,OAAO;AACjB,IAAI,QAAQ,EAAE;AACd,MAAM,IAAI;AACV,MAAM,WAAW,EAAE,YAAY,CAAC,WAAW;AAC3C,MAAM,WAAW,EAAE;AACnB,QAAQ,CAAC,oCAAoC,GAAG,YAAY,CAAC,EAAE;AAC/D,OAAO;AACP,KAAK;AACL,IAAI,IAAI,EAAE;AACV,MAAM,IAAI,EAAE,MAAM;AAClB,MAAM,OAAO,EAAE;AACf,QAAQ,WAAW,EAAE,YAAY,CAAC,WAAW;AAC7C,OAAO;AACP,MAAM,QAAQ,EAAE,EAAE;AAClB,KAAK;AACL,GAAG,CAAC;AACJ,CAAC;AACM,eAAe,8BAA8B,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE;AAChF,EAAE,IAAI,EAAE,CAAC;AACT,EAAE,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;AAC9D,EAAE,MAAM,WAAW,GAAG,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,WAAW,KAAK,IAAI,GAAG,EAAE,GAAG,8BAA8B,CAAC;AAC1H,EAAE,MAAM,SAAS,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC,CAAC;AACpD,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AACvB,CAAC;AACD,SAAS,gBAAgB,CAAC,KAAK,EAAE;AACjC,EAAE,IAAI,KAAK,CAAC,eAAe,EAAE;AAC7B,IAAI,OAAO,KAAK,CAAC,WAAW,CAAC;AAC7B,GAAG;AACH,EAAE,OAAO,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,WAAW,CAAC;AACjD,CAAC;AACM,eAAe,uBAAuB,CAAC,KAAK,EAAE,UAAU,EAAE;AACjE,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;AACvC,IAAI,OAAO,KAAK,CAAC,CAAC;AAClB,GAAG;AACH,EAAE,MAAM,IAAI,GAAG,mBAAmB,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5D,EAAE,MAAM,MAAM,GAAG;AACjB,IAAI,UAAU,EAAE,uBAAuB;AACvC,IAAI,IAAI,EAAE,OAAO;AACjB,IAAI,QAAQ,EAAE;AACd,MAAM,IAAI;AACV,MAAM,WAAW,EAAE;AACnB,QAAQ,CAAC,mCAAmC,GAAG,KAAK,CAAC,EAAE;AACvD,OAAO;AACP,KAAK;AACL,IAAI,IAAI,EAAE;AACV,MAAM,IAAI,EAAE,MAAM;AAClB,MAAM,OAAO,EAAE,EAAE;AACjB,MAAM,QAAQ,EAAE,EAAE;AAClB,KAAK;AACL,GAAG,CAAC;AACJ,EAAE,IAAI,KAAK,CAAC,WAAW,EAAE;AACzB,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;AACpD,GAAG;AACH,EAAE,IAAI,KAAK,CAAC,WAAW,EAAE;AACzB,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;AACxD,GAAG;AACH,EAAE,IAAI,KAAK,CAAC,IAAI,EAAE;AAClB,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;AAC3C,GAAG;AACH,EAAE,IAAI,UAAU,EAAE;AAClB,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,UAAU,CAAC;AAC7C,GAAG;AACH,EAAE,OAAO,MAAM,CAAC;AAChB,CAAC;AACM,eAAe,wBAAwB,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE;AAC1E,EAAE,IAAI,EAAE,CAAC;AACT,EAAE,MAAM,MAAM,GAAG,EAAE,CAAC;AACpB,EAAE,MAAM,WAAW,mBAAmB,IAAI,GAAG,EAAE,CAAC;AAChD,EAAE,MAAM,aAAa,mBAAmB,IAAI,GAAG,EAAE,CAAC;AAClD,EAAE,MAAM,OAAO,GAAGA,kCAAc,CAAC,EAAE,CAAC,CAAC;AACrC,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,8BAA8B,CAAC,MAAM,EAAE,QAAQ,EAAE;AAC/E,IAAI,WAAW,EAAE,OAAO,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,uBAAuB;AAC3E,GAAG,CAAC,CAAC;AACL,EAAE,IAAI,SAAS,EAAE;AACjB,IAAI,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,kBAAkB,IAAI,GAAG,EAAE,CAAC,CAAC;AACxE,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAC3B,GAAG;AACH,EAAE,MAAM,WAAW,GAAG,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,gBAAgB,KAAK,IAAI,GAAG,EAAE,GAAG,uBAAuB,CAAC;AACxH,EAAE,MAAM,QAAQ,GAAG,EAAE,CAAC;AACtB,EAAE,WAAW,MAAM,KAAK,IAAI,MAAM,CAAC,SAAS;AAC5C,IAAI;AACJ,MAAM,MAAM,EAAE,OAAO,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,WAAW;AAC5D,MAAM,MAAM,EAAE,OAAO,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,WAAW;AAC5D,MAAM,MAAM,EAAE,OAAO,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,WAAW;AAC5D,MAAM,MAAM,EAAE,OAAO,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,WAAW;AAC5D,KAAK;AACL,IAAI,OAAO,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,SAAS;AAChD,GAAG,EAAE;AACL,IAAI,QAAQ,CAAC,IAAI;AACjB,MAAM,OAAO,CAAC,YAAY;AAC1B,QAAQ,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;AAChD,QAAQ,IAAI,CAAC,MAAM,EAAE;AACrB,UAAU,OAAO;AACjB,SAAS;AACT,QAAQ,WAAW,MAAM,MAAM,IAAI,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACrE,UAAU,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE;AAC1B,YAAY,SAAS;AACrB,WAAW;AACX,UAAU,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,uBAAuB,EAAE;AACjE,YAAY,UAAU,CAAC,aAAa,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;AAC3D,WAAW;AACX,UAAU,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,wBAAwB,EAAE;AAClE,YAAY,UAAU,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AACzD,WAAW;AACX,SAAS;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC5B,OAAO,CAAC;AACR,KAAK,CAAC;AACN,GAAG;AACH,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC9B,EAAE,OAAO;AACT,IAAI,MAAM;AACV,IAAI,SAAS;AACb,IAAI,WAAW;AACf,IAAI,aAAa;AACjB,GAAG,CAAC;AACJ,CAAC;AACM,SAAS,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE;AACvF,EAAE,MAAM,QAAQ,mBAAmB,IAAI,GAAG,EAAE,CAAC;AAC7C,EAAE,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;AAC9B,IAAI,IAAI,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,mCAAmC,CAAC,EAAE;AACzE,MAAM,QAAQ,CAAC,GAAG;AAClB,QAAQ,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,mCAAmC,CAAC;AACvE,QAAQ,KAAK;AACb,OAAO,CAAC;AACR,KAAK;AACL,IAAI,IAAI,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,oCAAoC,CAAC,EAAE;AAC1E,MAAM,QAAQ,CAAC,GAAG;AAClB,QAAQ,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,oCAAoC,CAAC;AACxE,QAAQ,KAAK;AACb,OAAO,CAAC;AACR,KAAK;AACL,GAAG;AACH,EAAE,MAAM,YAAY,mBAAmB,IAAI,GAAG,EAAE,CAAC;AACjD,EAAE,WAAW,CAAC,OAAO;AACrB,IAAI,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,YAAY,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AACtF,GAAG,CAAC;AACJ,EAAE,IAAI,SAAS,EAAE;AACjB,IAAI,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,oCAAoC,CAAC,CAAC;AAC1F,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK;AAC9B,MAAM,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,mCAAmC,CAAC,CAAC;AACtF,MAAM,IAAI,CAAC,OAAO,EAAE;AACpB,QAAQ,OAAO;AACf,OAAO;AACP,MAAM,IAAI,aAAa,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE;AAC3D,QAAQ,UAAU,CAAC,YAAY,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;AACpD,QAAQ,UAAU,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AACnD,OAAO;AACP,KAAK,CAAC,CAAC;AACP,GAAG;AACH,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK;AAC5B,IAAI,IAAI,EAAE,CAAC;AACX,IAAI,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,mCAAmC,CAAC,KAAK,IAAI,GAAG,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,oCAAoC,CAAC,CAAC;AACtK,IAAI,aAAa,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;AAClD,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACzC,MAAM,IAAI,UAAU,EAAE;AACtB,QAAQ,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAACC,+BAAkB,CAAC,UAAU,CAAC,CAAC,CAAC;AACjE,OAAO;AACP,KAAK,CAAC,CAAC;AACP,IAAI,aAAa,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;AACnD,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1C,MAAM,IAAI,WAAW,EAAE;AACvB,QAAQ,KAAK,CAAC,IAAI,CAAC,MAAM,GAAGA,+BAAkB,CAAC,WAAW,CAAC,CAAC;AAC5D,OAAO;AACP,KAAK,CAAC,CAAC;AACP,GAAG,CAAC,CAAC;AACL,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC5B,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK;AAC1B,IAAI,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,kCAAkC,CAAC,CAAC;AAC7E,IAAI,aAAa,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;AACpD,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1C,MAAM,IAAI,WAAW,EAAE;AACvB,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;AACjC,UAAU,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;AAClC,SAAS;AACT,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAACA,+BAAkB,CAAC,WAAW,CAAC,CAAC,CAAC;AACjE,OAAO;AACP,KAAK,CAAC,CAAC;AACP,GAAG,CAAC,CAAC;AACL,EAAE,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAC/B,CAAC;AACM,eAAe,qBAAqB,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE;AACvE,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;AACnB,EAAE,IAAI,OAAO,CAAC,qBAAqB,IAAI,OAAO,CAAC,qBAAqB,EAAE;AACtE,IAAI,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,MAAM,+BAA+B;AAC1E,MAAM,MAAM;AACZ,MAAM;AACN,QAAQ,SAAS,EAAE,OAAO,CAAC,SAAS;AACpC,QAAQ,qBAAqB,EAAE,OAAO,CAAC,qBAAqB;AAC5D,QAAQ,qBAAqB,EAAE,OAAO,CAAC,qBAAqB;AAC5D,QAAQ,WAAW,EAAE,OAAO,CAAC,eAAe;AAC5C,QAAQ,MAAM,EAAE,OAAO,CAAC,MAAM;AAC9B,OAAO;AACP,KAAK,CAAC;AACN,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;AACjC,GAAG,MAAM;AACT,IAAI,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,MAAM,uBAAuB,CAAC,MAAM,EAAE;AAC7E,MAAM,SAAS,EAAE,OAAO,CAAC,SAAS;AAClC,MAAM,UAAU,EAAE,OAAO,CAAC,UAAU;AACpC,MAAM,UAAU,EAAE,OAAO,CAAC,UAAU;AACpC,MAAM,WAAW,EAAE,OAAO,CAAC,eAAe;AAC1C,MAAM,MAAM,EAAE,OAAO,CAAC,MAAM;AAC5B,KAAK,CAAC,CAAC;AACP,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC;AACnC,GAAG;AACH,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,MAAM,wBAAwB,CAAC,MAAM,EAAE,QAAQ,EAAE;AAC7G,IAAI,SAAS,EAAE,OAAO,CAAC,SAAS;AAChC,IAAI,WAAW,EAAE,OAAO,CAAC,WAAW;AACpC,IAAI,WAAW,EAAE,OAAO,CAAC,WAAW;AACpC,IAAI,WAAW,EAAE,OAAO,CAAC,WAAW;AACpC,IAAI,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;AAC9C,IAAI,uBAAuB,EAAE,OAAO,CAAC,uBAAuB;AAC5D,GAAG,CAAC,CAAC;AACL,EAAE,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;AACzE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AACvE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AACxE,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC;AACD,SAAS,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE;AACxC,EAAE,IAAI,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC5B,EAAE,IAAI,CAAC,GAAG,EAAE;AACZ,IAAI,GAAG,mBAAmB,IAAI,GAAG,EAAE,CAAC;AACpC,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACzB,GAAG;AACH,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC;AACD,SAAS,aAAa,CAAC,MAAM,EAAE,GAAG,EAAE;AACpC,EAAE,IAAI,EAAE,CAAC;AACT,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,EAAE,mBAAmB,IAAI,GAAG,EAAE,CAAC;AACzE;;ACxWO,MAAM,+BAA+B,CAAC;AAC7C,EAAE,WAAW,CAAC,OAAO,EAAE;AACvB,IAAI,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;AAC3B,GAAG;AACH,EAAE,OAAO,UAAU,CAAC,UAAU,EAAE,OAAO,EAAE;AACzC,IAAI,IAAI,IAAI,IAAI,OAAO,EAAE;AACzB,MAAM,OAAO;AACb,QAAQ,+BAA+B,CAAC,gBAAgB,CAAC,UAAU,EAAE,OAAO,CAAC;AAC7E,OAAO,CAAC;AACR,KAAK;AACL,IAAI,SAAS,cAAc,CAAC,EAAE,EAAE,YAAY,EAAE;AAC9C,MAAM,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,OAAO,YAAY,CAAC,EAAE;AACnE,QAAQ,OAAO,YAAY,CAAC;AAC5B,OAAO;AACP,MAAM,OAAO,YAAY,CAAC,EAAE,CAAC,CAAC;AAC9B,KAAK;AACL,IAAI,OAAO,mBAAmB,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,cAAc,KAAK;AACnE,MAAM,MAAM,QAAQ,GAAG,IAAI,+BAA+B,CAAC;AAC3D,QAAQ,EAAE,EAAE,cAAc,CAAC,EAAE;AAC7B,QAAQ,QAAQ,EAAE,cAAc;AAChC,QAAQ,MAAM,EAAE,OAAO,CAAC,MAAM;AAC9B,QAAQ,eAAe,EAAE,cAAc;AACvC,UAAU,cAAc,CAAC,EAAE;AAC3B,UAAU,OAAO,CAAC,eAAe;AACjC,SAAS;AACT,QAAQ,gBAAgB,EAAE,cAAc;AACxC,UAAU,cAAc,CAAC,EAAE;AAC3B,UAAU,OAAO,CAAC,gBAAgB;AAClC,SAAS;AACT,QAAQ,uBAAuB,EAAE,cAAc;AAC/C,UAAU,cAAc,CAAC,EAAE;AAC3B,UAAU,OAAO,CAAC,uBAAuB;AACzC,SAAS;AACT,OAAO,CAAC,CAAC;AACT,MAAM,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;AAC1C,MAAM,OAAO,QAAQ,CAAC;AACtB,KAAK,CAAC,CAAC;AACP,GAAG;AACH,EAAE,OAAO,gBAAgB,CAAC,UAAU,EAAE,OAAO,EAAE;AAC/C,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI;AACvB,MAAM,yPAAyP;AAC/P,KAAK,CAAC;AACN,IAAI,MAAM,MAAM,GAAG,UAAU,CAAC,iBAAiB;AAC/C,MAAM,sCAAsC;AAC5C,KAAK,CAAC;AACN,IAAI,MAAM,SAAS,GAAG,MAAM,GAAG,wBAAwB,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;AACrE,IAAI,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAChF,IAAI,IAAI,CAAC,QAAQ,EAAE;AACnB,MAAM,MAAM,IAAI,KAAK;AACrB,QAAQ,CAAC,uDAAuD,EAAE,OAAO,CAAC,MAAM,CAAC,kGAAkG,CAAC;AACpL,OAAO,CAAC;AACR,KAAK;AACL,IAAI,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;AACxC,MAAM,MAAM,EAAE,OAAO,CAAC,MAAM;AAC5B,KAAK,CAAC,CAAC;AACP,IAAI,MAAM,MAAM,GAAG,IAAI,+BAA+B,CAAC;AACvD,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE;AACpB,MAAM,eAAe,EAAE,OAAO,CAAC,eAAe;AAC9C,MAAM,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;AAChD,MAAM,uBAAuB,EAAE,OAAO,CAAC,uBAAuB;AAC9D,MAAM,MAAM;AACZ,MAAM,QAAQ;AACd,KAAK,CAAC,CAAC;AACP,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;AACtC,IAAI,OAAO,MAAM,CAAC;AAClB,GAAG;AACH,EAAE,eAAe,GAAG;AACpB,IAAI,OAAO,CAAC,gCAAgC,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAChE,GAAG;AACH,EAAE,MAAM,OAAO,CAAC,UAAU,EAAE;AAC5B,IAAI,IAAI,EAAE,CAAC;AACX,IAAI,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;AACjC,IAAI,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,UAAU,KAAK,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACpE,GAAG;AACH,EAAE,MAAM,IAAI,CAAC,OAAO,EAAE;AACtB,IAAI,IAAI,EAAE,CAAC;AACX,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;AAC1B,MAAM,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;AACzC,KAAK;AACL,IAAI,MAAM,MAAM,GAAG,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AACvG,IAAI,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC3C,IAAI,MAAM,EAAE,gBAAgB,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AACvD,IAAI,MAAM,MAAM,GAAG,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;AACtE,IAAI,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,qBAAqB;AACzD,MAAM,MAAM;AACZ,MAAM,QAAQ,CAAC,QAAQ;AACvB,MAAM;AACN,QAAQ,UAAU,EAAE,QAAQ,CAAC,UAAU;AACvC,QAAQ,qBAAqB,EAAE,QAAQ,CAAC,qBAAqB;AAC7D,QAAQ,qBAAqB,EAAE,QAAQ,CAAC,qBAAqB;AAC7D,QAAQ,WAAW,EAAE,QAAQ,CAAC,WAAW;AACzC,QAAQ,WAAW,EAAE,QAAQ,CAAC,WAAW;AACzC,QAAQ,WAAW,EAAE,QAAQ,CAAC,WAAW;AACzC,QAAQ,SAAS,EAAE,QAAQ,CAAC,SAAS;AACrC,QAAQ,gBAAgB,EAAE,IAAI,CAAC,OAAO,CAAC,gBAAgB;AACvD,QAAQ,eAAe,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe;AACrD,QAAQ,uBAAuB,EAAE,IAAI,CAAC,OAAO,CAAC,uBAAuB;AACrE,QAAQ,MAAM;AACd,OAAO;AACP,KAAK,CAAC;AACN,IAAI,MAAM,EAAE,kBAAkB,EAAE,GAAG,gBAAgB,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;AACvE,IAAI,MAAM,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;AACxC,MAAM,IAAI,EAAE,MAAM;AAClB,MAAM,QAAQ,EAAE,CAAC,GAAG,KAAK,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,MAAM;AACvD,QAAQ,WAAW,EAAE,CAAC,qBAAqB,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAC9D,QAAQ,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC;AACtD,OAAO,CAAC,CAAC;AACT,KAAK,CAAC,CAAC;AACP,IAAI,kBAAkB,EAAE,CAAC;AACzB,GAAG;AACH,EAAE,QAAQ,CAAC,QAAQ,EAAE;AACrB,IAAI,IAAI,QAAQ,KAAK,QAAQ,EAAE;AAC/B,MAAM,OAAO;AACb,KAAK;AACL,IAAI,IAAI,CAAC,UAAU,GAAG,YAAY;AAClC,MAAM,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,QAAQ,CAAC,CAAC;AACrD,MAAM,MAAM,QAAQ,CAAC,GAAG,CAAC;AACzB,QAAQ,EAAE;AACV,QAAQ,EAAE,EAAE,YAAY;AACxB,UAAU,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;AACnD,YAAY,KAAK,EAAE,+BAA+B,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI;AAC7E,YAAY,MAAM,EAAE,EAAE;AACtB,YAAY,cAAc,EAAEC,eAAI,CAAC,EAAE,EAAE;AACrC,WAAW,CAAC,CAAC;AACb,UAAU,IAAI;AACd,YAAY,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;AACxC,WAAW,CAAC,OAAO,KAAK,EAAE;AAC1B,YAAY,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAChC,WAAW;AACX,SAAS;AACT,OAAO,CAAC,CAAC;AACT,KAAK,CAAC;AACN,GAAG;AACH,CAAC;AACD,SAAS,aAAa,CAAC,MAAM,EAAE;AAC/B,EAAE,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC7B,EAAE,IAAI,OAAO,CAAC;AACd,EAAE,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;AAClD,EAAE,SAAS,gBAAgB,CAAC,IAAI,EAAE;AAClC,IAAI,OAAO,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,mBAAmB,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;AAC5F,IAAI,MAAM,YAAY,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,IAAI,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AACrE,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC3B,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAC;AAC7E,IAAI,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAClC,GAAG;AACH,EAAE,SAAS,kBAAkB,GAAG;AAChC,IAAI,MAAM,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,IAAI,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AACvE,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC;AACtE,GAAG;AACH,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAC9B,CAAC;AACM,SAAS,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE;AAClD,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;AACjB,EAAE,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,KAAK,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,kCAAkC,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,KAAK,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,mCAAmC,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,KAAK,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,oCAAoC,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;AAC5U,EAAE,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACtE,EAAE,OAAOC,YAAK;AACd,IAAI;AACJ,MAAM,QAAQ,EAAE;AAChB,QAAQ,WAAW,EAAE;AACrB,UAAU,CAACC,gCAAmB,GAAG,QAAQ;AACzC,UAAU,CAACC,uCAA0B,GAAG,QAAQ;AAChD,SAAS;AACT,OAAO;AACP,KAAK;AACL,IAAI,MAAM;AACV,GAAG,CAAC;AACJ;;AC7KO,MAAM,gCAAgC,CAAC;AAC9C,EAAE,OAAO,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AACrC,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,iBAAiB,CAAC,sCAAsC,CAAC,CAAC;AAC/E,IAAI,OAAO,IAAI,gCAAgC,CAAC;AAChD,MAAM,GAAG,OAAO;AAChB,MAAM,SAAS,EAAE,CAAC,GAAG,wBAAwB,CAAC,CAAC,CAAC,GAAG,EAAE;AACrD,KAAK,CAAC,CAAC;AACP,GAAG;AACH,EAAE,WAAW,CAAC,OAAO,EAAE;AACvB,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI;AACvB,MAAM,mOAAmO;AACzO,KAAK,CAAC;AACN,IAAI,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;AACvC,IAAI,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;AACjC,IAAI,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;AACnD,IAAI,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;AACrD,IAAI,IAAI,CAAC,uBAAuB,GAAG,OAAO,CAAC,uBAAuB,CAAC;AACnE,GAAG;AACH,EAAE,gBAAgB,GAAG;AACrB,IAAI,OAAO,kCAAkC,CAAC;AAC9C,GAAG;AACH,EAAE,MAAM,YAAY,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;AAChD,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,qBAAqB,EAAE;AACjD,MAAM,OAAO,KAAK,CAAC;AACnB,KAAK;AACL,IAAI,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI;AACxC,MAAM,CAAC,CAAC,KAAK,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC;AACjD,KAAK,CAAC;AACN,IAAI,IAAI,CAAC,QAAQ,EAAE;AACnB,MAAM,MAAM,IAAI,KAAK;AACrB,QAAQ,CAAC,sDAAsD,EAAE,QAAQ,CAAC,MAAM,CAAC,+FAA+F,CAAC;AACjL,OAAO,CAAC;AACR,KAAK;AACL,IAAI,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AACtC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;AACjE,IAAI,MAAM,MAAM,GAAG,oBAAoB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACzD,IAAI,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,qBAAqB;AACzD,MAAM,MAAM;AACZ,MAAM,QAAQ,CAAC,QAAQ;AACvB,MAAM;AACN,QAAQ,UAAU,EAAE,QAAQ,CAAC,UAAU;AACvC,QAAQ,UAAU,EAAE,QAAQ,CAAC,UAAU;AACvC,QAAQ,qBAAqB,EAAE,QAAQ,CAAC,qBAAqB;AAC7D,QAAQ,qBAAqB,EAAE,QAAQ,CAAC,qBAAqB;AAC7D,QAAQ,WAAW,EAAE,QAAQ,CAAC,WAAW;AACzC,QAAQ,WAAW,EAAE,QAAQ,CAAC,WAAW;AACzC,QAAQ,WAAW,EAAE,QAAQ,CAAC,WAAW;AACzC,QAAQ,WAAW,EAAE,QAAQ,CAAC,WAAW;AACzC,QAAQ,SAAS,EAAE,QAAQ,CAAC,SAAS;AACrC,QAAQ,eAAe,EAAE,IAAI,CAAC,eAAe;AAC7C,QAAQ,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;AAC/C,QAAQ,uBAAuB,EAAE,IAAI,CAAC,uBAAuB;AAC7D,QAAQ,MAAM,EAAE,IAAI,CAAC,MAAM;AAC3B,OAAO;AACP,KAAK,CAAC;AACN,IAAI,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,IAAI,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AACtE,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK;AACrB,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,gCAAgC,EAAE,QAAQ,CAAC,QAAQ,CAAC;AAC1G,KAAK,CAAC;AACN,IAAI,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;AAChC,MAAM,IAAI,CAACC,qCAAgB,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;AACrD,KAAK;AACL,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AAC9B,MAAM,IAAI,CAACA,qCAAgB,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;AACpD,KAAK;AACL,IAAI,OAAO,IAAI,CAAC;AAChB,GAAG;AACH;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend-module-msgraph",
3
3
  "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph",
4
- "version": "0.4.0",
4
+ "version": "0.4.1-next.0",
5
5
  "main": "dist/index.cjs.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "license": "Apache-2.0",
@@ -34,10 +34,10 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@azure/identity": "^2.1.0",
37
- "@backstage/backend-tasks": "^0.3.3",
37
+ "@backstage/backend-tasks": "^0.3.4-next.0",
38
38
  "@backstage/catalog-model": "^1.1.0",
39
39
  "@backstage/config": "^1.0.1",
40
- "@backstage/plugin-catalog-backend": "^1.3.0",
40
+ "@backstage/plugin-catalog-backend": "^1.3.1-next.0",
41
41
  "@microsoft/microsoft-graph-types": "^2.6.0",
42
42
  "@types/node-fetch": "^2.5.12",
43
43
  "lodash": "^4.17.21",
@@ -48,9 +48,9 @@
48
48
  "winston": "^3.2.1"
49
49
  },
50
50
  "devDependencies": {
51
- "@backstage/backend-common": "^0.14.1",
52
- "@backstage/backend-test-utils": "^0.1.26",
53
- "@backstage/cli": "^0.18.0",
51
+ "@backstage/backend-common": "^0.15.0-next.0",
52
+ "@backstage/backend-test-utils": "^0.1.27-next.0",
53
+ "@backstage/cli": "^0.18.1-next.0",
54
54
  "@types/lodash": "^4.14.151",
55
55
  "msw": "^0.44.0"
56
56
  },
@@ -59,5 +59,5 @@
59
59
  "config.d.ts"
60
60
  ],
61
61
  "configSchema": "config.d.ts",
62
- "gitHead": "999878d8f1ae30f6a15925816af2016cb9d717a1"
62
+ "gitHead": "fc3229c49caf6eced02ed9516199015bf4682664"
63
63
  }