@microsoft/m365-spec-parser 0.1.1-alpha.169a2b37a.0 → 0.1.1-alpha.2f5decfcc.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.
@@ -61,7 +61,7 @@ exports.ErrorType = void 0;
61
61
  ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
62
62
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
63
63
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
64
- ErrorType["MultipleAPIKeyNotSupported"] = "multiple-api-key-not-supported";
64
+ ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
65
65
  ErrorType["ListFailed"] = "list-failed";
66
66
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
67
67
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -117,7 +117,7 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
117
117
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
118
118
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
119
119
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
120
- ConstantString.MultipleAPIKeyNotSupported = "Multiple API keys are not supported. Please make sure that all selected APIs use the same API key.";
120
+ ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
121
121
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
122
122
  ConstantString.WrappedCardVersion = "devPreview";
123
123
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
@@ -130,6 +130,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
130
130
  ConstantString.TextBlockType = "TextBlock";
131
131
  ConstantString.ContainerType = "Container";
132
132
  ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
133
+ ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
133
134
  ConstantString.ResponseCodeFor20X = [
134
135
  "200",
135
136
  "201",
@@ -311,6 +312,9 @@ class Utils {
311
312
  }
312
313
  return paramResult;
313
314
  }
315
+ static containMultipleMediaTypes(bodyObject) {
316
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
317
+ }
314
318
  /**
315
319
  * Checks if the given API is supported.
316
320
  * @param {string} method - The HTTP method of the API.
@@ -332,9 +336,14 @@ class Utils {
332
336
  if (pathObj) {
333
337
  if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
334
338
  const securities = pathObj[method].security;
335
- const authArray = Utils.getAuthArray(securities, spec);
336
- if (!Utils.isSupportedAuth(authArray, options)) {
337
- return false;
339
+ const isTeamsAi = options.projectType === exports.ProjectType.TeamsAi;
340
+ const isCopilot = options.projectType === exports.ProjectType.Copilot;
341
+ // Teams AI project doesn't care about auth, it will use authProvider for user to implement
342
+ if (!isTeamsAi) {
343
+ const authArray = Utils.getAuthArray(securities, spec);
344
+ if (!Utils.isSupportedAuth(authArray, options)) {
345
+ return false;
346
+ }
338
347
  }
339
348
  const operationObject = pathObj[method];
340
349
  if (!options.allowMissingId && !operationObject.operationId) {
@@ -343,20 +352,22 @@ class Utils {
343
352
  const paramObject = operationObject.parameters;
344
353
  const requestBody = operationObject.requestBody;
345
354
  const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
346
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
347
- if (mediaTypesCount > 1) {
355
+ if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
348
356
  return false;
349
357
  }
350
- const responseJson = Utils.getResponseJson(operationObject);
358
+ const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
351
359
  if (Object.keys(responseJson).length === 0) {
352
360
  return false;
353
361
  }
362
+ // Teams AI project doesn't care about request parameters/body
363
+ if (isTeamsAi) {
364
+ return true;
365
+ }
354
366
  let requestBodyParamResult = {
355
367
  requiredNum: 0,
356
368
  optionalNum: 0,
357
369
  isValid: true,
358
370
  };
359
- const isCopilot = options.projectType === exports.ProjectType.Copilot;
360
371
  if (requestJsonBody) {
361
372
  const requestBodySchema = requestJsonBody.schema;
362
373
  if (isCopilot && requestBodySchema.type !== "object") {
@@ -397,31 +408,20 @@ class Utils {
397
408
  }
398
409
  return false;
399
410
  }
400
- static isSupportedAuth(authSchemaArray, options) {
401
- if (authSchemaArray.length === 0) {
411
+ static isSupportedAuth(authSchemeArray, options) {
412
+ if (authSchemeArray.length === 0) {
402
413
  return true;
403
414
  }
404
- if (options.allowAPIKeyAuth || options.allowOauth2) {
415
+ if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
405
416
  // Currently we don't support multiple auth in one operation
406
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
417
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
407
418
  return false;
408
419
  }
409
- for (const auths of authSchemaArray) {
420
+ for (const auths of authSchemeArray) {
410
421
  if (auths.length === 1) {
411
- if (!options.allowOauth2 &&
412
- options.allowAPIKeyAuth &&
413
- Utils.isAPIKeyAuth(auths[0].authSchema)) {
414
- return true;
415
- }
416
- else if (!options.allowAPIKeyAuth &&
417
- options.allowOauth2 &&
418
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
419
- return true;
420
- }
421
- else if (options.allowAPIKeyAuth &&
422
- options.allowOauth2 &&
423
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
424
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
422
+ if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
423
+ (options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
424
+ (options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
425
425
  return true;
426
426
  }
427
427
  }
@@ -429,13 +429,17 @@ class Utils {
429
429
  }
430
430
  return false;
431
431
  }
432
- static isAPIKeyAuth(authSchema) {
433
- return authSchema.type === "apiKey";
432
+ static isBearerTokenAuth(authScheme) {
433
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
434
434
  }
435
- static isBearerTokenAuth(authSchema) {
436
- return (authSchema.type === "oauth2" ||
437
- authSchema.type === "openIdConnect" ||
438
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
435
+ static isAPIKeyAuth(authScheme) {
436
+ return authScheme.type === "apiKey";
437
+ }
438
+ static isOAuthWithAuthCodeFlow(authScheme) {
439
+ if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
440
+ return true;
441
+ }
442
+ return false;
439
443
  }
440
444
  static getAuthArray(securities, spec) {
441
445
  var _a;
@@ -448,7 +452,7 @@ class Utils {
448
452
  for (const name in security) {
449
453
  const auth = securitySchemas[name];
450
454
  authArray.push({
451
- authSchema: auth,
455
+ authScheme: auth,
452
456
  name: name,
453
457
  });
454
458
  }
@@ -463,18 +467,19 @@ class Utils {
463
467
  static updateFirstLetter(str) {
464
468
  return str.charAt(0).toUpperCase() + str.slice(1);
465
469
  }
466
- static getResponseJson(operationObject) {
470
+ static getResponseJson(operationObject, isTeamsAiProject = false) {
467
471
  var _a, _b;
468
472
  let json = {};
469
473
  for (const code of ConstantString.ResponseCodeFor20X) {
470
474
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
471
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
472
- if (mediaTypesCount > 1) {
473
- return {};
474
- }
475
475
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
476
476
  json = responseObject.content["application/json"];
477
- break;
477
+ if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
478
+ json = {};
479
+ }
480
+ else {
481
+ break;
482
+ }
478
483
  }
479
484
  }
480
485
  return json;
@@ -612,6 +617,7 @@ class Utils {
612
617
  Utils.updateParameterWithInputType(schema, parameter);
613
618
  }
614
619
  if (isRequired && schema.default === undefined) {
620
+ parameter.isRequired = true;
615
621
  requiredParams.push(parameter);
616
622
  }
617
623
  else {
@@ -675,6 +681,7 @@ class Utils {
675
681
  }
676
682
  if (param.in !== "header" && param.in !== "cookie") {
677
683
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
684
+ parameter.isRequired = true;
678
685
  requiredParams.push(parameter);
679
686
  }
680
687
  else {
@@ -725,7 +732,6 @@ class Utils {
725
732
  for (const path in paths) {
726
733
  const methods = paths[path];
727
734
  for (const method in methods) {
728
- // For developer preview, only support GET operation with only 1 parameter without auth
729
735
  if (Utils.isSupportedApi(method, path, spec, options)) {
730
736
  const operationObject = methods[method];
731
737
  result[`${method.toUpperCase()} ${path}`] = operationObject;
@@ -809,6 +815,19 @@ class Utils {
809
815
  }
810
816
  return safeRegistrationIdEnvName;
811
817
  }
818
+ static getAllAPICount(spec) {
819
+ let count = 0;
820
+ const paths = spec.paths;
821
+ for (const path in paths) {
822
+ const methods = paths[path];
823
+ for (const method in methods) {
824
+ if (ConstantString.AllOperationMethods.includes(method)) {
825
+ count++;
826
+ }
827
+ }
828
+ }
829
+ return count;
830
+ }
812
831
  }
813
832
 
814
833
  // Copyright (c) Microsoft Corporation.
@@ -965,7 +984,7 @@ class ManifestUpdater {
965
984
  };
966
985
  return apiPlugin;
967
986
  }
968
- static updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, auth) {
987
+ static updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
969
988
  return __awaiter(this, void 0, void 0, function* () {
970
989
  try {
971
990
  const originalManifest = yield fs__default['default'].readJSON(manifestPath);
@@ -981,10 +1000,10 @@ class ManifestUpdater {
981
1000
  apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
982
1001
  commands: commands,
983
1002
  };
984
- if (auth) {
985
- if (Utils.isAPIKeyAuth(auth)) {
986
- auth = auth;
987
- const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${auth.name}_${ConstantString.RegistrationIdPostfix}`);
1003
+ if (authInfo) {
1004
+ const auth = authInfo.authScheme;
1005
+ if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
1006
+ const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
988
1007
  composeExtension.authorization = {
989
1008
  authType: "apiSecretServiceAuth",
990
1009
  apiSecretServiceAuthConfiguration: {
@@ -992,11 +1011,12 @@ class ManifestUpdater {
992
1011
  },
993
1012
  };
994
1013
  }
995
- else if (Utils.isBearerTokenAuth(auth)) {
1014
+ else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
1015
+ const safeOAuth2RegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.OAuthRegistrationIdPostFix}`);
996
1016
  composeExtension.authorization = {
997
- authType: "microsoftEntra",
998
- microsoftEntraConfiguration: {
999
- supportsSingleSignOn: true,
1017
+ authType: "oAuth2.0",
1018
+ oAuthConfiguration: {
1019
+ oauthConfigurationId: `\${{${safeOAuth2RegistrationId}}}`,
1000
1020
  },
1001
1021
  };
1002
1022
  updatedPart.webApplicationInfo = {
@@ -1323,6 +1343,7 @@ class SpecParser {
1323
1343
  allowMissingId: true,
1324
1344
  allowSwagger: true,
1325
1345
  allowAPIKeyAuth: false,
1346
+ allowBearerTokenAuth: false,
1326
1347
  allowMultipleParameters: false,
1327
1348
  allowOauth2: false,
1328
1349
  allowMethods: ["get", "post"],
@@ -1385,7 +1406,11 @@ class SpecParser {
1385
1406
  yield this.loadSpec();
1386
1407
  const spec = this.spec;
1387
1408
  const apiMap = this.getAllSupportedAPIs(spec);
1388
- const result = [];
1409
+ const result = {
1410
+ validAPIs: [],
1411
+ allAPICount: 0,
1412
+ validAPICount: 0,
1413
+ };
1389
1414
  for (const apiKey in apiMap) {
1390
1415
  const apiResult = {
1391
1416
  api: "",
@@ -1410,13 +1435,15 @@ class SpecParser {
1410
1435
  const authArray = Utils.getAuthArray(operation.security, spec);
1411
1436
  for (const auths of authArray) {
1412
1437
  if (auths.length === 1) {
1413
- apiResult.auth = auths[0].authSchema;
1438
+ apiResult.auth = auths[0];
1414
1439
  break;
1415
1440
  }
1416
1441
  }
1417
1442
  apiResult.api = apiKey;
1418
- result.push(apiResult);
1443
+ result.validAPIs.push(apiResult);
1419
1444
  }
1445
+ result.allAPICount = Utils.getAllAPICount(spec);
1446
+ result.validAPICount = result.validAPIs.length;
1420
1447
  return result;
1421
1448
  }
1422
1449
  catch (err) {
@@ -1514,23 +1541,23 @@ class SpecParser {
1514
1541
  const newSpecs = yield this.getFilteredSpecs(filter, signal);
1515
1542
  const newUnResolvedSpec = newSpecs[0];
1516
1543
  const newSpec = newSpecs[1];
1517
- const AuthSet = new Set();
1518
- let hasMultipleAPIKeyAuth = false;
1544
+ const authSet = new Set();
1545
+ let hasMultipleAuth = false;
1519
1546
  for (const url in newSpec.paths) {
1520
1547
  for (const method in newSpec.paths[url]) {
1521
1548
  const operation = newSpec.paths[url][method];
1522
1549
  const authArray = Utils.getAuthArray(operation.security, newSpec);
1523
1550
  if (authArray && authArray.length > 0) {
1524
- AuthSet.add(authArray[0][0].authSchema);
1525
- if (AuthSet.size > 1) {
1526
- hasMultipleAPIKeyAuth = true;
1551
+ authSet.add(authArray[0][0]);
1552
+ if (authSet.size > 1) {
1553
+ hasMultipleAuth = true;
1527
1554
  break;
1528
1555
  }
1529
1556
  }
1530
1557
  }
1531
1558
  }
1532
- if (hasMultipleAPIKeyAuth) {
1533
- throw new SpecParserError(ConstantString.MultipleAPIKeyNotSupported, exports.ErrorType.MultipleAPIKeyNotSupported);
1559
+ if (hasMultipleAuth && this.options.projectType !== exports.ProjectType.TeamsAi) {
1560
+ throw new SpecParserError(ConstantString.MultipleAuthNotSupported, exports.ErrorType.MultipleAuthNotSupported);
1534
1561
  }
1535
1562
  let resultStr;
1536
1563
  if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
@@ -1569,8 +1596,8 @@ class SpecParser {
1569
1596
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1570
1597
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1571
1598
  }
1572
- const auth = Array.from(AuthSet)[0];
1573
- const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, auth);
1599
+ const authInfo = Array.from(authSet)[0];
1600
+ const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
1574
1601
  yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1575
1602
  result.warnings.push(...warnings);
1576
1603
  }