@microsoft/m365-spec-parser 0.1.1-alpha.cf377d39f.0 → 0.1.1-alpha.e17ffd4d1.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";
@@ -92,7 +92,13 @@ exports.ValidationStatus = void 0;
92
92
  ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
93
93
  ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
94
94
  ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
95
- })(exports.ValidationStatus || (exports.ValidationStatus = {}));
95
+ })(exports.ValidationStatus || (exports.ValidationStatus = {}));
96
+ exports.ProjectType = void 0;
97
+ (function (ProjectType) {
98
+ ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
99
+ ProjectType[ProjectType["SME"] = 1] = "SME";
100
+ ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
101
+ })(exports.ProjectType || (exports.ProjectType = {}));
96
102
 
97
103
  // Copyright (c) Microsoft Corporation.
98
104
  class ConstantString {
@@ -111,7 +117,8 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
111
117
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
112
118
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
113
119
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
114
- 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
+ ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
115
122
  ConstantString.WrappedCardVersion = "devPreview";
116
123
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
117
124
  ConstantString.WrappedCardResponseLayout = "list";
@@ -123,6 +130,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
123
130
  ConstantString.TextBlockType = "TextBlock";
124
131
  ConstantString.ContainerType = "Container";
125
132
  ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
133
+ ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
126
134
  ConstantString.ResponseCodeFor20X = [
127
135
  "200",
128
136
  "201",
@@ -182,7 +190,8 @@ ConstantString.FullDescriptionMaxLens = 4000;
182
190
  ConstantString.CommandDescriptionMaxLens = 128;
183
191
  ConstantString.ParameterDescriptionMaxLens = 128;
184
192
  ConstantString.CommandTitleMaxLens = 32;
185
- ConstantString.ParameterTitleMaxLens = 32;
193
+ ConstantString.ParameterTitleMaxLens = 32;
194
+ ConstantString.SMERequiredParamsMaxNum = 5;
186
195
 
187
196
  // Copyright (c) Microsoft Corporation.
188
197
  class SpecParserError extends Error {
@@ -194,7 +203,18 @@ class SpecParserError extends Error {
194
203
 
195
204
  // Copyright (c) Microsoft Corporation.
196
205
  class Utils {
197
- static checkParameters(paramObject) {
206
+ static hasNestedObjectInSchema(schema) {
207
+ if (schema.type === "object") {
208
+ for (const property in schema.properties) {
209
+ const nestedSchema = schema.properties[property];
210
+ if (nestedSchema.type === "object") {
211
+ return true;
212
+ }
213
+ }
214
+ }
215
+ return false;
216
+ }
217
+ static checkParameters(paramObject, isCopilot) {
198
218
  const paramResult = {
199
219
  requiredNum: 0,
200
220
  optionalNum: 0,
@@ -206,7 +226,20 @@ class Utils {
206
226
  for (let i = 0; i < paramObject.length; i++) {
207
227
  const param = paramObject[i];
208
228
  const schema = param.schema;
229
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
230
+ paramResult.isValid = false;
231
+ continue;
232
+ }
209
233
  const isRequiredWithoutDefault = param.required && schema.default === undefined;
234
+ if (isCopilot) {
235
+ if (isRequiredWithoutDefault) {
236
+ paramResult.requiredNum = paramResult.requiredNum + 1;
237
+ }
238
+ else {
239
+ paramResult.optionalNum = paramResult.optionalNum + 1;
240
+ }
241
+ continue;
242
+ }
210
243
  if (param.in === "header" || param.in === "cookie") {
211
244
  if (isRequiredWithoutDefault) {
212
245
  paramResult.isValid = false;
@@ -233,7 +266,7 @@ class Utils {
233
266
  }
234
267
  return paramResult;
235
268
  }
236
- static checkPostBody(schema, isRequired = false) {
269
+ static checkPostBody(schema, isRequired = false, isCopilot = false) {
237
270
  var _a;
238
271
  const paramResult = {
239
272
  requiredNum: 0,
@@ -244,6 +277,10 @@ class Utils {
244
277
  return paramResult;
245
278
  }
246
279
  const isRequiredWithoutDefault = isRequired && schema.default === undefined;
280
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
281
+ paramResult.isValid = false;
282
+ return paramResult;
283
+ }
247
284
  if (schema.type === "string" ||
248
285
  schema.type === "integer" ||
249
286
  schema.type === "boolean" ||
@@ -262,19 +299,22 @@ class Utils {
262
299
  if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
263
300
  isRequired = true;
264
301
  }
265
- const result = Utils.checkPostBody(properties[property], isRequired);
302
+ const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
266
303
  paramResult.requiredNum += result.requiredNum;
267
304
  paramResult.optionalNum += result.optionalNum;
268
305
  paramResult.isValid = paramResult.isValid && result.isValid;
269
306
  }
270
307
  }
271
308
  else {
272
- if (isRequiredWithoutDefault) {
309
+ if (isRequiredWithoutDefault && !isCopilot) {
273
310
  paramResult.isValid = false;
274
311
  }
275
312
  }
276
313
  return paramResult;
277
314
  }
315
+ static containMultipleMediaTypes(bodyObject) {
316
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
317
+ }
278
318
  /**
279
319
  * Checks if the given API is supported.
280
320
  * @param {string} method - The HTTP method of the API.
@@ -289,32 +329,40 @@ class Utils {
289
329
  * 5. response body should be “application/json” and not empty, and response code should be 20X
290
330
  * 6. only support request body with “application/json” content type
291
331
  */
292
- static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
332
+ static isSupportedApi(method, path, spec, options) {
333
+ var _a;
293
334
  const pathObj = spec.paths[path];
294
335
  method = method.toLocaleLowerCase();
295
336
  if (pathObj) {
296
- if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
297
- pathObj[method]) {
337
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
298
338
  const securities = pathObj[method].security;
299
- const authArray = Utils.getAuthArray(securities, spec);
300
- if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
301
- 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
+ }
302
347
  }
303
348
  const operationObject = pathObj[method];
304
- if (!allowMissingId && !operationObject.operationId) {
349
+ if (!options.allowMissingId && !operationObject.operationId) {
305
350
  return false;
306
351
  }
307
352
  const paramObject = operationObject.parameters;
308
353
  const requestBody = operationObject.requestBody;
309
354
  const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
310
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
311
- if (mediaTypesCount > 1) {
355
+ if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
312
356
  return false;
313
357
  }
314
- const responseJson = Utils.getResponseJson(operationObject);
358
+ const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
315
359
  if (Object.keys(responseJson).length === 0) {
316
360
  return false;
317
361
  }
362
+ // Teams AI project doesn't care about request parameters/body
363
+ if (isTeamsAi) {
364
+ return true;
365
+ }
318
366
  let requestBodyParamResult = {
319
367
  requiredNum: 0,
320
368
  optionalNum: 0,
@@ -322,18 +370,26 @@ class Utils {
322
370
  };
323
371
  if (requestJsonBody) {
324
372
  const requestBodySchema = requestJsonBody.schema;
325
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required);
373
+ if (isCopilot && requestBodySchema.type !== "object") {
374
+ return false;
375
+ }
376
+ requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
326
377
  }
327
378
  if (!requestBodyParamResult.isValid) {
328
379
  return false;
329
380
  }
330
- const paramResult = Utils.checkParameters(paramObject);
381
+ const paramResult = Utils.checkParameters(paramObject, isCopilot);
331
382
  if (!paramResult.isValid) {
332
383
  return false;
333
384
  }
385
+ // Copilot support arbitrary parameters
386
+ if (isCopilot) {
387
+ return true;
388
+ }
334
389
  if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
335
- if (allowMultipleParameters &&
336
- requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
390
+ if (options.allowMultipleParameters &&
391
+ requestBodyParamResult.requiredNum + paramResult.requiredNum <=
392
+ ConstantString.SMERequiredParamsMaxNum) {
337
393
  return true;
338
394
  }
339
395
  return false;
@@ -352,29 +408,31 @@ class Utils {
352
408
  }
353
409
  return false;
354
410
  }
355
- static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
411
+ static isSupportedAuth(authSchemaArray, options) {
356
412
  if (authSchemaArray.length === 0) {
357
413
  return true;
358
414
  }
359
- if (allowAPIKeyAuth || allowOauth2) {
415
+ if (options.allowAPIKeyAuth || options.allowOauth2) {
360
416
  // Currently we don't support multiple auth in one operation
361
417
  if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
362
418
  return false;
363
419
  }
364
420
  for (const auths of authSchemaArray) {
365
421
  if (auths.length === 1) {
366
- if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
422
+ if (!options.allowOauth2 &&
423
+ options.allowAPIKeyAuth &&
424
+ Utils.isAPIKeyAuth(auths[0].authSchema)) {
367
425
  return true;
368
426
  }
369
- else if (!allowAPIKeyAuth &&
370
- allowOauth2 &&
371
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
427
+ else if (!options.allowAPIKeyAuth &&
428
+ options.allowOauth2 &&
429
+ Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema)) {
372
430
  return true;
373
431
  }
374
- else if (allowAPIKeyAuth &&
375
- allowOauth2 &&
432
+ else if (options.allowAPIKeyAuth &&
433
+ options.allowOauth2 &&
376
434
  (Utils.isAPIKeyAuth(auths[0].authSchema) ||
377
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
435
+ Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema))) {
378
436
  return true;
379
437
  }
380
438
  }
@@ -385,10 +443,11 @@ class Utils {
385
443
  static isAPIKeyAuth(authSchema) {
386
444
  return authSchema.type === "apiKey";
387
445
  }
388
- static isBearerTokenAuth(authSchema) {
389
- return (authSchema.type === "oauth2" ||
390
- authSchema.type === "openIdConnect" ||
391
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
446
+ static isOAuthWithAuthCodeFlow(authSchema) {
447
+ if (authSchema.type === "oauth2" && authSchema.flows && authSchema.flows.authorizationCode) {
448
+ return true;
449
+ }
450
+ return false;
392
451
  }
393
452
  static getAuthArray(securities, spec) {
394
453
  var _a;
@@ -416,18 +475,19 @@ class Utils {
416
475
  static updateFirstLetter(str) {
417
476
  return str.charAt(0).toUpperCase() + str.slice(1);
418
477
  }
419
- static getResponseJson(operationObject) {
478
+ static getResponseJson(operationObject, isTeamsAiProject = false) {
420
479
  var _a, _b;
421
480
  let json = {};
422
481
  for (const code of ConstantString.ResponseCodeFor20X) {
423
482
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
424
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
425
- if (mediaTypesCount > 1) {
426
- return {};
427
- }
428
483
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
429
484
  json = responseObject.content["application/json"];
430
- break;
485
+ if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
486
+ json = {};
487
+ }
488
+ else {
489
+ break;
490
+ }
431
491
  }
432
492
  }
433
493
  return json;
@@ -501,7 +561,7 @@ class Utils {
501
561
  }
502
562
  return errors;
503
563
  }
504
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
564
+ static validateServer(spec, options) {
505
565
  const errors = [];
506
566
  let hasTopLevelServers = false;
507
567
  let hasPathLevelServers = false;
@@ -522,7 +582,7 @@ class Utils {
522
582
  }
523
583
  for (const method in methods) {
524
584
  const operationObject = methods[method];
525
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
585
+ if (Utils.isSupportedApi(method, path, spec, options)) {
526
586
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
527
587
  hasOperationLevelServers = true;
528
588
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -609,7 +669,7 @@ class Utils {
609
669
  param.value = schema.default;
610
670
  }
611
671
  }
612
- static parseApiInfo(operationItem, allowMultipleParameters) {
672
+ static parseApiInfo(operationItem, options) {
613
673
  var _a, _b;
614
674
  const requiredParams = [];
615
675
  const optionalParams = [];
@@ -623,7 +683,7 @@ class Utils {
623
683
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
624
684
  };
625
685
  const schema = param.schema;
626
- if (allowMultipleParameters && schema) {
686
+ if (options.allowMultipleParameters && schema) {
627
687
  Utils.updateParameterWithInputType(schema, parameter);
628
688
  }
629
689
  if (param.in !== "header" && param.in !== "cookie") {
@@ -641,7 +701,7 @@ class Utils {
641
701
  const requestJson = requestBody.content["application/json"];
642
702
  if (Object.keys(requestJson).length !== 0) {
643
703
  const schema = requestJson.schema;
644
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
704
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
645
705
  requiredParams.push(...requiredP);
646
706
  optionalParams.push(...optionalP);
647
707
  }
@@ -672,14 +732,13 @@ class Utils {
672
732
  }
673
733
  return [command, warning];
674
734
  }
675
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
735
+ static listSupportedAPIs(spec, options) {
676
736
  const paths = spec.paths;
677
737
  const result = {};
678
738
  for (const path in paths) {
679
739
  const methods = paths[path];
680
740
  for (const method in methods) {
681
- // For developer preview, only support GET operation with only 1 parameter without auth
682
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
741
+ if (Utils.isSupportedApi(method, path, spec, options)) {
683
742
  const operationObject = methods[method];
684
743
  result[`${method.toUpperCase()} ${path}`] = operationObject;
685
744
  }
@@ -687,7 +746,7 @@ class Utils {
687
746
  }
688
747
  return result;
689
748
  }
690
- static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
749
+ static validateSpec(spec, parser, isSwaggerFile, options) {
691
750
  const errors = [];
692
751
  const warnings = [];
693
752
  if (isSwaggerFile) {
@@ -697,7 +756,7 @@ class Utils {
697
756
  });
698
757
  }
699
758
  // Server validation
700
- const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
759
+ const serverErrors = Utils.validateServer(spec, options);
701
760
  errors.push(...serverErrors);
702
761
  // Remote reference not supported
703
762
  const refPaths = parser.$refs.paths();
@@ -710,7 +769,7 @@ class Utils {
710
769
  });
711
770
  }
712
771
  // No supported API
713
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
772
+ const apiMap = Utils.listSupportedAPIs(spec, options);
714
773
  if (Object.keys(apiMap).length === 0) {
715
774
  errors.push({
716
775
  type: exports.ErrorType.NoSupportedApi,
@@ -766,14 +825,14 @@ class Utils {
766
825
 
767
826
  // Copyright (c) Microsoft Corporation.
768
827
  class SpecFilter {
769
- static specFilter(filter, unResolveSpec, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
828
+ static specFilter(filter, unResolveSpec, resolvedSpec, options) {
770
829
  try {
771
830
  const newSpec = Object.assign({}, unResolveSpec);
772
831
  const newPaths = {};
773
832
  for (const filterItem of filter) {
774
833
  const [method, path] = filterItem.split(" ");
775
834
  const methodName = method.toLowerCase();
776
- if (!Utils.isSupportedApi(methodName, path, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
835
+ if (!Utils.isSupportedApi(methodName, path, resolvedSpec, options)) {
777
836
  continue;
778
837
  }
779
838
  if (!newPaths[path]) {
@@ -799,47 +858,171 @@ class SpecFilter {
799
858
 
800
859
  // Copyright (c) Microsoft Corporation.
801
860
  class ManifestUpdater {
802
- static updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, spec, allowMultipleParameters, auth, isMe) {
861
+ static updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options) {
862
+ return __awaiter(this, void 0, void 0, function* () {
863
+ const manifest = yield fs__default['default'].readJSON(manifestPath);
864
+ const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
865
+ manifest.plugins = [
866
+ {
867
+ pluginFile: apiPluginRelativePath,
868
+ },
869
+ ];
870
+ ManifestUpdater.updateManifestDescription(manifest, spec);
871
+ const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
872
+ const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, options);
873
+ return [manifest, apiPlugin];
874
+ });
875
+ }
876
+ static updateManifestDescription(manifest, spec) {
803
877
  var _a, _b;
878
+ manifest.description = {
879
+ short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
880
+ full: (_b = ((_a = spec.info.description) !== null && _a !== void 0 ? _a : manifest.description.full)) === null || _b === void 0 ? void 0 : _b.slice(0, ConstantString.FullDescriptionMaxLens),
881
+ };
882
+ }
883
+ static mapOpenAPISchemaToFuncParam(schema, method, pathUrl) {
884
+ let parameter;
885
+ if (schema.type === "string" ||
886
+ schema.type === "boolean" ||
887
+ schema.type === "integer" ||
888
+ schema.type === "number" ||
889
+ schema.type === "array") {
890
+ parameter = schema;
891
+ }
892
+ else {
893
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), exports.ErrorType.UpdateManifestFailed);
894
+ }
895
+ return parameter;
896
+ }
897
+ static generatePluginManifestSchema(spec, specRelativePath, options) {
898
+ var _a, _b, _c;
899
+ const functions = [];
900
+ const functionNames = [];
901
+ const paths = spec.paths;
902
+ for (const pathUrl in paths) {
903
+ const pathItem = paths[pathUrl];
904
+ if (pathItem) {
905
+ const operations = pathItem;
906
+ for (const method in operations) {
907
+ if (options.allowMethods.includes(method)) {
908
+ const operationItem = operations[method];
909
+ if (operationItem) {
910
+ const operationId = operationItem.operationId;
911
+ const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
912
+ const paramObject = operationItem.parameters;
913
+ const requestBody = operationItem.requestBody;
914
+ const parameters = {
915
+ type: "object",
916
+ properties: {},
917
+ required: [],
918
+ };
919
+ if (paramObject) {
920
+ for (let i = 0; i < paramObject.length; i++) {
921
+ const param = paramObject[i];
922
+ const schema = param.schema;
923
+ parameters.properties[param.name] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
924
+ if (param.required) {
925
+ parameters.required.push(param.name);
926
+ }
927
+ if (!parameters.properties[param.name].description) {
928
+ parameters.properties[param.name].description = (_b = param.description) !== null && _b !== void 0 ? _b : "";
929
+ }
930
+ }
931
+ }
932
+ if (requestBody) {
933
+ const requestJsonBody = requestBody.content["application/json"];
934
+ const requestBodySchema = requestJsonBody.schema;
935
+ if (requestBodySchema.type === "object") {
936
+ if (requestBodySchema.required) {
937
+ parameters.required.push(...requestBodySchema.required);
938
+ }
939
+ for (const property in requestBodySchema.properties) {
940
+ const schema = requestBodySchema.properties[property];
941
+ parameters.properties[property] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
942
+ }
943
+ }
944
+ else {
945
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), exports.ErrorType.UpdateManifestFailed);
946
+ }
947
+ }
948
+ const funcObj = {
949
+ name: operationId,
950
+ description: description,
951
+ parameters: parameters,
952
+ };
953
+ functions.push(funcObj);
954
+ functionNames.push(operationId);
955
+ }
956
+ }
957
+ }
958
+ }
959
+ }
960
+ const apiPlugin = {
961
+ schema_version: "v2",
962
+ name_for_human: spec.info.title,
963
+ description_for_human: (_c = spec.info.description) !== null && _c !== void 0 ? _c : "<Please add description of the plugin>",
964
+ functions: functions,
965
+ runtimes: [
966
+ {
967
+ type: "OpenApi",
968
+ auth: {
969
+ type: "none", // TODO, support auth in the future
970
+ },
971
+ spec: {
972
+ url: specRelativePath,
973
+ },
974
+ run_for_functions: functionNames,
975
+ },
976
+ ],
977
+ };
978
+ return apiPlugin;
979
+ }
980
+ static updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
804
981
  return __awaiter(this, void 0, void 0, function* () {
805
982
  try {
806
983
  const originalManifest = yield fs__default['default'].readJSON(manifestPath);
807
984
  const updatedPart = {};
808
- const [commands, warnings] = yield ManifestUpdater.generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters);
809
- const composeExtension = {
810
- composeExtensionType: "apiBased",
811
- apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
812
- commands: commands,
813
- };
814
- if (auth) {
815
- if (Utils.isAPIKeyAuth(auth)) {
816
- auth = auth;
817
- const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${auth.name}_${ConstantString.RegistrationIdPostfix}`);
818
- composeExtension.authorization = {
819
- authType: "apiSecretServiceAuth",
820
- apiSecretServiceAuthConfiguration: {
821
- apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
822
- },
823
- };
824
- }
825
- else if (Utils.isBearerTokenAuth(auth)) {
826
- composeExtension.authorization = {
827
- authType: "microsoftEntra",
828
- microsoftEntraConfiguration: {
829
- supportsSingleSignOn: true,
830
- },
831
- };
832
- updatedPart.webApplicationInfo = {
833
- id: "${{AAD_APP_CLIENT_ID}}",
834
- resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
835
- };
985
+ updatedPart.composeExtensions = [];
986
+ let warnings = [];
987
+ if (options.projectType === exports.ProjectType.SME) {
988
+ const updateResult = yield ManifestUpdater.generateCommands(spec, manifestPath, options, adaptiveCardFolder);
989
+ const commands = updateResult[0];
990
+ warnings = updateResult[1];
991
+ const composeExtension = {
992
+ composeExtensionType: "apiBased",
993
+ apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
994
+ commands: commands,
995
+ };
996
+ if (authInfo) {
997
+ let auth = authInfo.authSchema;
998
+ if (Utils.isAPIKeyAuth(auth)) {
999
+ auth = auth;
1000
+ const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
1001
+ composeExtension.authorization = {
1002
+ authType: "apiSecretServiceAuth",
1003
+ apiSecretServiceAuthConfiguration: {
1004
+ apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
1005
+ },
1006
+ };
1007
+ }
1008
+ else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
1009
+ const safeOAuth2RegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.OAuthRegistrationIdPostFix}`);
1010
+ composeExtension.authorization = {
1011
+ authType: "oAuth2.0",
1012
+ oAuthConfiguration: {
1013
+ oauthConfigurationId: `\${{${safeOAuth2RegistrationId}}}`,
1014
+ },
1015
+ };
1016
+ updatedPart.webApplicationInfo = {
1017
+ id: "${{AAD_APP_CLIENT_ID}}",
1018
+ resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
1019
+ };
1020
+ }
836
1021
  }
1022
+ updatedPart.composeExtensions = [composeExtension];
837
1023
  }
838
- updatedPart.description = {
839
- short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
840
- full: (_b = ((_a = spec.info.description) !== null && _a !== void 0 ? _a : originalManifest.description.full)) === null || _b === void 0 ? void 0 : _b.slice(0, ConstantString.FullDescriptionMaxLens),
841
- };
842
- updatedPart.composeExtensions = isMe === undefined || isMe === true ? [composeExtension] : [];
1024
+ updatedPart.description = originalManifest.description;
1025
+ ManifestUpdater.updateManifestDescription(updatedPart, spec);
843
1026
  const updatedManifest = Object.assign(Object.assign({}, originalManifest), updatedPart);
844
1027
  return [updatedManifest, warnings];
845
1028
  }
@@ -848,7 +1031,8 @@ class ManifestUpdater {
848
1031
  }
849
1032
  });
850
1033
  }
851
- static generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters) {
1034
+ static generateCommands(spec, manifestPath, options, adaptiveCardFolder) {
1035
+ var _a;
852
1036
  return __awaiter(this, void 0, void 0, function* () {
853
1037
  const paths = spec.paths;
854
1038
  const commands = [];
@@ -860,14 +1044,16 @@ class ManifestUpdater {
860
1044
  const operations = pathItem;
861
1045
  // Currently only support GET and POST method
862
1046
  for (const method in operations) {
863
- if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
1047
+ if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
864
1048
  const operationItem = operations[method];
865
1049
  if (operationItem) {
866
- const [command, warning] = Utils.parseApiInfo(operationItem, allowMultipleParameters);
867
- const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
868
- command.apiResponseRenderingTemplateFile = (yield fs__default['default'].pathExists(adaptiveCardPath))
869
- ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
870
- : "";
1050
+ const [command, warning] = Utils.parseApiInfo(operationItem, options);
1051
+ if (adaptiveCardFolder) {
1052
+ const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
1053
+ command.apiResponseRenderingTemplateFile = (yield fs__default['default'].pathExists(adaptiveCardPath))
1054
+ ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
1055
+ : "";
1056
+ }
871
1057
  if (warning) {
872
1058
  warnings.push(warning);
873
1059
  }
@@ -1153,6 +1339,8 @@ class SpecParser {
1153
1339
  allowAPIKeyAuth: false,
1154
1340
  allowMultipleParameters: false,
1155
1341
  allowOauth2: false,
1342
+ allowMethods: ["get", "post"],
1343
+ projectType: exports.ProjectType.SME,
1156
1344
  };
1157
1345
  this.pathOrSpec = pathOrDoc;
1158
1346
  this.parser = new SwaggerParser__default['default']();
@@ -1186,7 +1374,7 @@ class SpecParser {
1186
1374
  ],
1187
1375
  };
1188
1376
  }
1189
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1377
+ return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
1190
1378
  }
1191
1379
  catch (err) {
1192
1380
  throw new SpecParserError(err.toString(), exports.ErrorType.ValidateFailed);
@@ -1267,7 +1455,7 @@ class SpecParser {
1267
1455
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1268
1456
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1269
1457
  }
1270
- const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1458
+ const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options);
1271
1459
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1272
1460
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1273
1461
  }
@@ -1282,15 +1470,55 @@ class SpecParser {
1282
1470
  }
1283
1471
  });
1284
1472
  }
1473
+ /**
1474
+ * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1475
+ * @param manifestPath A file path of the Teams app manifest file to update.
1476
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1477
+ * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1478
+ * @param pluginFilePath File path of the api plugin file to generate.
1479
+ */
1480
+ generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
1481
+ return __awaiter(this, void 0, void 0, function* () {
1482
+ const result = {
1483
+ allSuccess: true,
1484
+ warnings: [],
1485
+ };
1486
+ try {
1487
+ const newSpecs = yield this.getFilteredSpecs(filter, signal);
1488
+ const newUnResolvedSpec = newSpecs[0];
1489
+ const newSpec = newSpecs[1];
1490
+ let resultStr;
1491
+ if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
1492
+ resultStr = jsyaml__default['default'].dump(newUnResolvedSpec);
1493
+ }
1494
+ else {
1495
+ resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1496
+ }
1497
+ yield fs__default['default'].outputFile(outputSpecPath, resultStr);
1498
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1499
+ throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1500
+ }
1501
+ const [updatedManifest, apiPlugin] = yield ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options);
1502
+ yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1503
+ yield fs__default['default'].outputJSON(pluginFilePath, apiPlugin, { spaces: 2 });
1504
+ }
1505
+ catch (err) {
1506
+ if (err instanceof SpecParserError) {
1507
+ throw err;
1508
+ }
1509
+ throw new SpecParserError(err.toString(), exports.ErrorType.GenerateFailed);
1510
+ }
1511
+ return result;
1512
+ });
1513
+ }
1285
1514
  /**
1286
1515
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1287
1516
  * @param manifestPath A file path of the Teams app manifest file to update.
1288
1517
  * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1289
1518
  * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1290
1519
  * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
1291
- * @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
1292
1520
  */
1293
- generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal, isMe) {
1521
+ generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1294
1522
  return __awaiter(this, void 0, void 0, function* () {
1295
1523
  const result = {
1296
1524
  allSuccess: true,
@@ -1300,23 +1528,23 @@ class SpecParser {
1300
1528
  const newSpecs = yield this.getFilteredSpecs(filter, signal);
1301
1529
  const newUnResolvedSpec = newSpecs[0];
1302
1530
  const newSpec = newSpecs[1];
1303
- const AuthSet = new Set();
1304
- let hasMultipleAPIKeyAuth = false;
1531
+ const authSet = new Set();
1532
+ let hasMultipleAuth = false;
1305
1533
  for (const url in newSpec.paths) {
1306
1534
  for (const method in newSpec.paths[url]) {
1307
1535
  const operation = newSpec.paths[url][method];
1308
1536
  const authArray = Utils.getAuthArray(operation.security, newSpec);
1309
1537
  if (authArray && authArray.length > 0) {
1310
- AuthSet.add(authArray[0][0].authSchema);
1311
- if (AuthSet.size > 1) {
1312
- hasMultipleAPIKeyAuth = true;
1538
+ authSet.add(authArray[0][0]);
1539
+ if (authSet.size > 1) {
1540
+ hasMultipleAuth = true;
1313
1541
  break;
1314
1542
  }
1315
1543
  }
1316
1544
  }
1317
1545
  }
1318
- if (hasMultipleAPIKeyAuth) {
1319
- throw new SpecParserError(ConstantString.MultipleAPIKeyNotSupported, exports.ErrorType.MultipleAPIKeyNotSupported);
1546
+ if (hasMultipleAuth && this.options.projectType !== exports.ProjectType.TeamsAi) {
1547
+ throw new SpecParserError(ConstantString.MultipleAuthNotSupported, exports.ErrorType.MultipleAuthNotSupported);
1320
1548
  }
1321
1549
  let resultStr;
1322
1550
  if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
@@ -1326,26 +1554,28 @@ class SpecParser {
1326
1554
  resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1327
1555
  }
1328
1556
  yield fs__default['default'].outputFile(outputSpecPath, resultStr);
1329
- for (const url in newSpec.paths) {
1330
- for (const method in newSpec.paths[url]) {
1331
- // paths object may contain description/summary, so we need to check if it is a operation object
1332
- if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
1333
- const operation = newSpec.paths[url][method];
1334
- try {
1335
- const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1336
- const fileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.json`);
1337
- const wrappedCard = wrapAdaptiveCard(card, jsonPath);
1338
- yield fs__default['default'].outputJSON(fileName, wrappedCard, { spaces: 2 });
1339
- const dataFileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.data.json`);
1340
- yield fs__default['default'].outputJSON(dataFileName, {}, { spaces: 2 });
1341
- }
1342
- catch (err) {
1343
- result.allSuccess = false;
1344
- result.warnings.push({
1345
- type: exports.WarningType.GenerateCardFailed,
1346
- content: err.toString(),
1347
- data: operation.operationId,
1348
- });
1557
+ if (adaptiveCardFolder) {
1558
+ for (const url in newSpec.paths) {
1559
+ for (const method in newSpec.paths[url]) {
1560
+ // paths object may contain description/summary which is not a http method, so we need to check if it is a operation object
1561
+ if (this.options.allowMethods.includes(method)) {
1562
+ const operation = newSpec.paths[url][method];
1563
+ try {
1564
+ const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1565
+ const fileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.json`);
1566
+ const wrappedCard = wrapAdaptiveCard(card, jsonPath);
1567
+ yield fs__default['default'].outputJSON(fileName, wrappedCard, { spaces: 2 });
1568
+ const dataFileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.data.json`);
1569
+ yield fs__default['default'].outputJSON(dataFileName, {}, { spaces: 2 });
1570
+ }
1571
+ catch (err) {
1572
+ result.allSuccess = false;
1573
+ result.warnings.push({
1574
+ type: exports.WarningType.GenerateCardFailed,
1575
+ content: err.toString(),
1576
+ data: operation.operationId,
1577
+ });
1578
+ }
1349
1579
  }
1350
1580
  }
1351
1581
  }
@@ -1353,8 +1583,8 @@ class SpecParser {
1353
1583
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1354
1584
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1355
1585
  }
1356
- const auth = Array.from(AuthSet)[0];
1357
- const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, newSpec, this.options.allowMultipleParameters, auth, isMe);
1586
+ const authInfo = Array.from(authSet)[0];
1587
+ const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
1358
1588
  yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1359
1589
  result.warnings.push(...warnings);
1360
1590
  }
@@ -1386,7 +1616,7 @@ class SpecParser {
1386
1616
  if (this.apiMap !== undefined) {
1387
1617
  return this.apiMap;
1388
1618
  }
1389
- const result = Utils.listSupportedAPIs(spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1619
+ const result = Utils.listSupportedAPIs(spec, this.options);
1390
1620
  this.apiMap = result;
1391
1621
  return result;
1392
1622
  }