@microsoft/m365-spec-parser 0.1.1-alpha.78701ec6a.0 → 0.1.1-alpha.a372ccf67.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";
@@ -69,6 +69,7 @@ exports.ErrorType = void 0;
69
69
  ErrorType["GenerateAdaptiveCardFailed"] = "generate-adaptive-card-failed";
70
70
  ErrorType["GenerateFailed"] = "generate-failed";
71
71
  ErrorType["ValidateFailed"] = "validate-failed";
72
+ ErrorType["GetSpecFailed"] = "get-spec-failed";
72
73
  ErrorType["Cancelled"] = "cancelled";
73
74
  ErrorType["Unknown"] = "unknown";
74
75
  })(exports.ErrorType || (exports.ErrorType = {}));
@@ -91,7 +92,13 @@ exports.ValidationStatus = void 0;
91
92
  ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
92
93
  ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
93
94
  ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
94
- })(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 = {}));
95
102
 
96
103
  // Copyright (c) Microsoft Corporation.
97
104
  class ConstantString {
@@ -110,7 +117,8 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
110
117
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
111
118
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
112
119
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
113
- 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";
114
122
  ConstantString.WrappedCardVersion = "devPreview";
115
123
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
116
124
  ConstantString.WrappedCardResponseLayout = "list";
@@ -122,6 +130,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
122
130
  ConstantString.TextBlockType = "TextBlock";
123
131
  ConstantString.ContainerType = "Container";
124
132
  ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
133
+ ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
125
134
  ConstantString.ResponseCodeFor20X = [
126
135
  "200",
127
136
  "201",
@@ -181,7 +190,8 @@ ConstantString.FullDescriptionMaxLens = 4000;
181
190
  ConstantString.CommandDescriptionMaxLens = 128;
182
191
  ConstantString.ParameterDescriptionMaxLens = 128;
183
192
  ConstantString.CommandTitleMaxLens = 32;
184
- ConstantString.ParameterTitleMaxLens = 32;
193
+ ConstantString.ParameterTitleMaxLens = 32;
194
+ ConstantString.SMERequiredParamsMaxNum = 5;
185
195
 
186
196
  // Copyright (c) Microsoft Corporation.
187
197
  class SpecParserError extends Error {
@@ -193,7 +203,18 @@ class SpecParserError extends Error {
193
203
 
194
204
  // Copyright (c) Microsoft Corporation.
195
205
  class Utils {
196
- 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) {
197
218
  const paramResult = {
198
219
  requiredNum: 0,
199
220
  optionalNum: 0,
@@ -205,7 +226,20 @@ class Utils {
205
226
  for (let i = 0; i < paramObject.length; i++) {
206
227
  const param = paramObject[i];
207
228
  const schema = param.schema;
229
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
230
+ paramResult.isValid = false;
231
+ continue;
232
+ }
208
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
+ }
209
243
  if (param.in === "header" || param.in === "cookie") {
210
244
  if (isRequiredWithoutDefault) {
211
245
  paramResult.isValid = false;
@@ -232,7 +266,7 @@ class Utils {
232
266
  }
233
267
  return paramResult;
234
268
  }
235
- static checkPostBody(schema, isRequired = false) {
269
+ static checkPostBody(schema, isRequired = false, isCopilot = false) {
236
270
  var _a;
237
271
  const paramResult = {
238
272
  requiredNum: 0,
@@ -243,6 +277,10 @@ class Utils {
243
277
  return paramResult;
244
278
  }
245
279
  const isRequiredWithoutDefault = isRequired && schema.default === undefined;
280
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
281
+ paramResult.isValid = false;
282
+ return paramResult;
283
+ }
246
284
  if (schema.type === "string" ||
247
285
  schema.type === "integer" ||
248
286
  schema.type === "boolean" ||
@@ -261,19 +299,22 @@ class Utils {
261
299
  if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
262
300
  isRequired = true;
263
301
  }
264
- const result = Utils.checkPostBody(properties[property], isRequired);
302
+ const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
265
303
  paramResult.requiredNum += result.requiredNum;
266
304
  paramResult.optionalNum += result.optionalNum;
267
305
  paramResult.isValid = paramResult.isValid && result.isValid;
268
306
  }
269
307
  }
270
308
  else {
271
- if (isRequiredWithoutDefault) {
309
+ if (isRequiredWithoutDefault && !isCopilot) {
272
310
  paramResult.isValid = false;
273
311
  }
274
312
  }
275
313
  return paramResult;
276
314
  }
315
+ static containMultipleMediaTypes(bodyObject) {
316
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
317
+ }
277
318
  /**
278
319
  * Checks if the given API is supported.
279
320
  * @param {string} method - The HTTP method of the API.
@@ -288,32 +329,40 @@ class Utils {
288
329
  * 5. response body should be “application/json” and not empty, and response code should be 20X
289
330
  * 6. only support request body with “application/json” content type
290
331
  */
291
- static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
332
+ static isSupportedApi(method, path, spec, options) {
333
+ var _a;
292
334
  const pathObj = spec.paths[path];
293
335
  method = method.toLocaleLowerCase();
294
336
  if (pathObj) {
295
- if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
296
- pathObj[method]) {
337
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
297
338
  const securities = pathObj[method].security;
298
- const authArray = Utils.getAuthArray(securities, spec);
299
- if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
300
- 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
+ }
301
347
  }
302
348
  const operationObject = pathObj[method];
303
- if (!allowMissingId && !operationObject.operationId) {
349
+ if (!options.allowMissingId && !operationObject.operationId) {
304
350
  return false;
305
351
  }
306
352
  const paramObject = operationObject.parameters;
307
353
  const requestBody = operationObject.requestBody;
308
354
  const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
309
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
310
- if (mediaTypesCount > 1) {
355
+ if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
311
356
  return false;
312
357
  }
313
- const responseJson = Utils.getResponseJson(operationObject);
358
+ const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
314
359
  if (Object.keys(responseJson).length === 0) {
315
360
  return false;
316
361
  }
362
+ // Teams AI project doesn't care about request parameters/body
363
+ if (isTeamsAi) {
364
+ return true;
365
+ }
317
366
  let requestBodyParamResult = {
318
367
  requiredNum: 0,
319
368
  optionalNum: 0,
@@ -321,18 +370,26 @@ class Utils {
321
370
  };
322
371
  if (requestJsonBody) {
323
372
  const requestBodySchema = requestJsonBody.schema;
324
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required);
373
+ if (isCopilot && requestBodySchema.type !== "object") {
374
+ return false;
375
+ }
376
+ requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
325
377
  }
326
378
  if (!requestBodyParamResult.isValid) {
327
379
  return false;
328
380
  }
329
- const paramResult = Utils.checkParameters(paramObject);
381
+ const paramResult = Utils.checkParameters(paramObject, isCopilot);
330
382
  if (!paramResult.isValid) {
331
383
  return false;
332
384
  }
385
+ // Copilot support arbitrary parameters
386
+ if (isCopilot) {
387
+ return true;
388
+ }
333
389
  if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
334
- if (allowMultipleParameters &&
335
- requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
390
+ if (options.allowMultipleParameters &&
391
+ requestBodyParamResult.requiredNum + paramResult.requiredNum <=
392
+ ConstantString.SMERequiredParamsMaxNum) {
336
393
  return true;
337
394
  }
338
395
  return false;
@@ -351,29 +408,31 @@ class Utils {
351
408
  }
352
409
  return false;
353
410
  }
354
- static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
411
+ static isSupportedAuth(authSchemaArray, options) {
355
412
  if (authSchemaArray.length === 0) {
356
413
  return true;
357
414
  }
358
- if (allowAPIKeyAuth || allowOauth2) {
415
+ if (options.allowAPIKeyAuth || options.allowOauth2) {
359
416
  // Currently we don't support multiple auth in one operation
360
417
  if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
361
418
  return false;
362
419
  }
363
420
  for (const auths of authSchemaArray) {
364
421
  if (auths.length === 1) {
365
- if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
422
+ if (!options.allowOauth2 &&
423
+ options.allowAPIKeyAuth &&
424
+ Utils.isAPIKeyAuth(auths[0].authSchema)) {
366
425
  return true;
367
426
  }
368
- else if (!allowAPIKeyAuth &&
369
- allowOauth2 &&
370
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
427
+ else if (!options.allowAPIKeyAuth &&
428
+ options.allowOauth2 &&
429
+ Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema)) {
371
430
  return true;
372
431
  }
373
- else if (allowAPIKeyAuth &&
374
- allowOauth2 &&
432
+ else if (options.allowAPIKeyAuth &&
433
+ options.allowOauth2 &&
375
434
  (Utils.isAPIKeyAuth(auths[0].authSchema) ||
376
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
435
+ Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema))) {
377
436
  return true;
378
437
  }
379
438
  }
@@ -384,10 +443,11 @@ class Utils {
384
443
  static isAPIKeyAuth(authSchema) {
385
444
  return authSchema.type === "apiKey";
386
445
  }
387
- static isBearerTokenAuth(authSchema) {
388
- return (authSchema.type === "oauth2" ||
389
- authSchema.type === "openIdConnect" ||
390
- (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;
391
451
  }
392
452
  static getAuthArray(securities, spec) {
393
453
  var _a;
@@ -415,18 +475,19 @@ class Utils {
415
475
  static updateFirstLetter(str) {
416
476
  return str.charAt(0).toUpperCase() + str.slice(1);
417
477
  }
418
- static getResponseJson(operationObject) {
478
+ static getResponseJson(operationObject, isTeamsAiProject = false) {
419
479
  var _a, _b;
420
480
  let json = {};
421
481
  for (const code of ConstantString.ResponseCodeFor20X) {
422
482
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
423
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
424
- if (mediaTypesCount > 1) {
425
- return {};
426
- }
427
483
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
428
484
  json = responseObject.content["application/json"];
429
- break;
485
+ if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
486
+ json = {};
487
+ }
488
+ else {
489
+ break;
490
+ }
430
491
  }
431
492
  }
432
493
  return json;
@@ -500,7 +561,7 @@ class Utils {
500
561
  }
501
562
  return errors;
502
563
  }
503
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
564
+ static validateServer(spec, options) {
504
565
  const errors = [];
505
566
  let hasTopLevelServers = false;
506
567
  let hasPathLevelServers = false;
@@ -521,7 +582,7 @@ class Utils {
521
582
  }
522
583
  for (const method in methods) {
523
584
  const operationObject = methods[method];
524
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
585
+ if (Utils.isSupportedApi(method, path, spec, options)) {
525
586
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
526
587
  hasOperationLevelServers = true;
527
588
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -608,7 +669,7 @@ class Utils {
608
669
  param.value = schema.default;
609
670
  }
610
671
  }
611
- static parseApiInfo(operationItem, allowMultipleParameters) {
672
+ static parseApiInfo(operationItem, options) {
612
673
  var _a, _b;
613
674
  const requiredParams = [];
614
675
  const optionalParams = [];
@@ -622,7 +683,7 @@ class Utils {
622
683
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
623
684
  };
624
685
  const schema = param.schema;
625
- if (allowMultipleParameters && schema) {
686
+ if (options.allowMultipleParameters && schema) {
626
687
  Utils.updateParameterWithInputType(schema, parameter);
627
688
  }
628
689
  if (param.in !== "header" && param.in !== "cookie") {
@@ -640,7 +701,7 @@ class Utils {
640
701
  const requestJson = requestBody.content["application/json"];
641
702
  if (Object.keys(requestJson).length !== 0) {
642
703
  const schema = requestJson.schema;
643
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
704
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
644
705
  requiredParams.push(...requiredP);
645
706
  optionalParams.push(...optionalP);
646
707
  }
@@ -671,14 +732,13 @@ class Utils {
671
732
  }
672
733
  return [command, warning];
673
734
  }
674
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
735
+ static listSupportedAPIs(spec, options) {
675
736
  const paths = spec.paths;
676
737
  const result = {};
677
738
  for (const path in paths) {
678
739
  const methods = paths[path];
679
740
  for (const method in methods) {
680
- // For developer preview, only support GET operation with only 1 parameter without auth
681
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
741
+ if (Utils.isSupportedApi(method, path, spec, options)) {
682
742
  const operationObject = methods[method];
683
743
  result[`${method.toUpperCase()} ${path}`] = operationObject;
684
744
  }
@@ -686,7 +746,7 @@ class Utils {
686
746
  }
687
747
  return result;
688
748
  }
689
- static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
749
+ static validateSpec(spec, parser, isSwaggerFile, options) {
690
750
  const errors = [];
691
751
  const warnings = [];
692
752
  if (isSwaggerFile) {
@@ -696,7 +756,7 @@ class Utils {
696
756
  });
697
757
  }
698
758
  // Server validation
699
- const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
759
+ const serverErrors = Utils.validateServer(spec, options);
700
760
  errors.push(...serverErrors);
701
761
  // Remote reference not supported
702
762
  const refPaths = parser.$refs.paths();
@@ -709,7 +769,7 @@ class Utils {
709
769
  });
710
770
  }
711
771
  // No supported API
712
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
772
+ const apiMap = Utils.listSupportedAPIs(spec, options);
713
773
  if (Object.keys(apiMap).length === 0) {
714
774
  errors.push({
715
775
  type: exports.ErrorType.NoSupportedApi,
@@ -765,14 +825,14 @@ class Utils {
765
825
 
766
826
  // Copyright (c) Microsoft Corporation.
767
827
  class SpecFilter {
768
- static specFilter(filter, unResolveSpec, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
828
+ static specFilter(filter, unResolveSpec, resolvedSpec, options) {
769
829
  try {
770
830
  const newSpec = Object.assign({}, unResolveSpec);
771
831
  const newPaths = {};
772
832
  for (const filterItem of filter) {
773
833
  const [method, path] = filterItem.split(" ");
774
834
  const methodName = method.toLowerCase();
775
- if (!Utils.isSupportedApi(methodName, path, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
835
+ if (!Utils.isSupportedApi(methodName, path, resolvedSpec, options)) {
776
836
  continue;
777
837
  }
778
838
  if (!newPaths[path]) {
@@ -798,47 +858,171 @@ class SpecFilter {
798
858
 
799
859
  // Copyright (c) Microsoft Corporation.
800
860
  class ManifestUpdater {
801
- static updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, spec, allowMultipleParameters, auth) {
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) {
802
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) {
803
981
  return __awaiter(this, void 0, void 0, function* () {
804
982
  try {
805
983
  const originalManifest = yield fs__default['default'].readJSON(manifestPath);
806
984
  const updatedPart = {};
807
- const [commands, warnings] = yield ManifestUpdater.generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters);
808
- const composeExtension = {
809
- composeExtensionType: "apiBased",
810
- apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
811
- commands: commands,
812
- };
813
- if (auth) {
814
- if (Utils.isAPIKeyAuth(auth)) {
815
- auth = auth;
816
- const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${auth.name}_${ConstantString.RegistrationIdPostfix}`);
817
- composeExtension.authorization = {
818
- authType: "apiSecretServiceAuth",
819
- apiSecretServiceAuthConfiguration: {
820
- apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
821
- },
822
- };
823
- }
824
- else if (Utils.isBearerTokenAuth(auth)) {
825
- composeExtension.authorization = {
826
- authType: "microsoftEntra",
827
- microsoftEntraConfiguration: {
828
- supportsSingleSignOn: true,
829
- },
830
- };
831
- updatedPart.webApplicationInfo = {
832
- id: "${{AAD_APP_CLIENT_ID}}",
833
- resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
834
- };
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
+ }
835
1021
  }
1022
+ updatedPart.composeExtensions = [composeExtension];
836
1023
  }
837
- updatedPart.description = {
838
- short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
839
- 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),
840
- };
841
- updatedPart.composeExtensions = [composeExtension];
1024
+ updatedPart.description = originalManifest.description;
1025
+ ManifestUpdater.updateManifestDescription(updatedPart, spec);
842
1026
  const updatedManifest = Object.assign(Object.assign({}, originalManifest), updatedPart);
843
1027
  return [updatedManifest, warnings];
844
1028
  }
@@ -847,7 +1031,8 @@ class ManifestUpdater {
847
1031
  }
848
1032
  });
849
1033
  }
850
- static generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters) {
1034
+ static generateCommands(spec, manifestPath, options, adaptiveCardFolder) {
1035
+ var _a;
851
1036
  return __awaiter(this, void 0, void 0, function* () {
852
1037
  const paths = spec.paths;
853
1038
  const commands = [];
@@ -859,14 +1044,16 @@ class ManifestUpdater {
859
1044
  const operations = pathItem;
860
1045
  // Currently only support GET and POST method
861
1046
  for (const method in operations) {
862
- if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
1047
+ if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
863
1048
  const operationItem = operations[method];
864
1049
  if (operationItem) {
865
- const [command, warning] = Utils.parseApiInfo(operationItem, allowMultipleParameters);
866
- const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
867
- command.apiResponseRenderingTemplateFile = (yield fs__default['default'].pathExists(adaptiveCardPath))
868
- ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
869
- : "";
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
+ }
870
1057
  if (warning) {
871
1058
  warnings.push(warning);
872
1059
  }
@@ -1152,6 +1339,8 @@ class SpecParser {
1152
1339
  allowAPIKeyAuth: false,
1153
1340
  allowMultipleParameters: false,
1154
1341
  allowOauth2: false,
1342
+ allowMethods: ["get", "post"],
1343
+ projectType: exports.ProjectType.SME,
1155
1344
  };
1156
1345
  this.pathOrSpec = pathOrDoc;
1157
1346
  this.parser = new SwaggerParser__default['default']();
@@ -1185,7 +1374,7 @@ class SpecParser {
1185
1374
  ],
1186
1375
  };
1187
1376
  }
1188
- 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);
1189
1378
  }
1190
1379
  catch (err) {
1191
1380
  throw new SpecParserError(err.toString(), exports.ErrorType.ValidateFailed);
@@ -1252,49 +1441,110 @@ class SpecParser {
1252
1441
  }
1253
1442
  });
1254
1443
  }
1444
+ /**
1445
+ * Generate specs according to the filters.
1446
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1447
+ */
1448
+ getFilteredSpecs(filter, signal) {
1449
+ return __awaiter(this, void 0, void 0, function* () {
1450
+ try {
1451
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1452
+ throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1453
+ }
1454
+ yield this.loadSpec();
1455
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1456
+ throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1457
+ }
1458
+ const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options);
1459
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1460
+ throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1461
+ }
1462
+ const newSpec = (yield this.parser.dereference(newUnResolvedSpec));
1463
+ return [newUnResolvedSpec, newSpec];
1464
+ }
1465
+ catch (err) {
1466
+ if (err instanceof SpecParserError) {
1467
+ throw err;
1468
+ }
1469
+ throw new SpecParserError(err.toString(), exports.ErrorType.GetSpecFailed);
1470
+ }
1471
+ });
1472
+ }
1255
1473
  /**
1256
1474
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1257
1475
  * @param manifestPath A file path of the Teams app manifest file to update.
1258
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.
1259
1477
  * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1260
- * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
1478
+ * @param pluginFilePath File path of the api plugin file to generate.
1261
1479
  */
1262
- generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1480
+ generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
1263
1481
  return __awaiter(this, void 0, void 0, function* () {
1264
1482
  const result = {
1265
1483
  allSuccess: true,
1266
1484
  warnings: [],
1267
1485
  };
1268
1486
  try {
1269
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1270
- throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
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);
1271
1493
  }
1272
- yield this.loadSpec();
1273
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1274
- throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1494
+ else {
1495
+ resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1275
1496
  }
1276
- const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1497
+ yield fs__default['default'].outputFile(outputSpecPath, resultStr);
1277
1498
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1278
1499
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1279
1500
  }
1280
- const newSpec = (yield this.parser.dereference(newUnResolvedSpec));
1281
- const AuthSet = new Set();
1282
- let hasMultipleAPIKeyAuth = false;
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
+ }
1514
+ /**
1515
+ * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1516
+ * @param manifestPath A file path of the Teams app manifest file to update.
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.
1518
+ * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
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.
1520
+ */
1521
+ generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1522
+ return __awaiter(this, void 0, void 0, function* () {
1523
+ const result = {
1524
+ allSuccess: true,
1525
+ warnings: [],
1526
+ };
1527
+ try {
1528
+ const newSpecs = yield this.getFilteredSpecs(filter, signal);
1529
+ const newUnResolvedSpec = newSpecs[0];
1530
+ const newSpec = newSpecs[1];
1531
+ const authSet = new Set();
1532
+ let hasMultipleAuth = false;
1283
1533
  for (const url in newSpec.paths) {
1284
1534
  for (const method in newSpec.paths[url]) {
1285
1535
  const operation = newSpec.paths[url][method];
1286
1536
  const authArray = Utils.getAuthArray(operation.security, newSpec);
1287
1537
  if (authArray && authArray.length > 0) {
1288
- AuthSet.add(authArray[0][0].authSchema);
1289
- if (AuthSet.size > 1) {
1290
- hasMultipleAPIKeyAuth = true;
1538
+ authSet.add(authArray[0][0]);
1539
+ if (authSet.size > 1) {
1540
+ hasMultipleAuth = true;
1291
1541
  break;
1292
1542
  }
1293
1543
  }
1294
1544
  }
1295
1545
  }
1296
- if (hasMultipleAPIKeyAuth) {
1297
- 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);
1298
1548
  }
1299
1549
  let resultStr;
1300
1550
  if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
@@ -1304,26 +1554,28 @@ class SpecParser {
1304
1554
  resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1305
1555
  }
1306
1556
  yield fs__default['default'].outputFile(outputSpecPath, resultStr);
1307
- for (const url in newSpec.paths) {
1308
- for (const method in newSpec.paths[url]) {
1309
- // paths object may contain description/summary, so we need to check if it is a operation object
1310
- if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
1311
- const operation = newSpec.paths[url][method];
1312
- try {
1313
- const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1314
- const fileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.json`);
1315
- const wrappedCard = wrapAdaptiveCard(card, jsonPath);
1316
- yield fs__default['default'].outputJSON(fileName, wrappedCard, { spaces: 2 });
1317
- const dataFileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.data.json`);
1318
- yield fs__default['default'].outputJSON(dataFileName, {}, { spaces: 2 });
1319
- }
1320
- catch (err) {
1321
- result.allSuccess = false;
1322
- result.warnings.push({
1323
- type: exports.WarningType.GenerateCardFailed,
1324
- content: err.toString(),
1325
- data: operation.operationId,
1326
- });
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
+ }
1327
1579
  }
1328
1580
  }
1329
1581
  }
@@ -1331,8 +1583,8 @@ class SpecParser {
1331
1583
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1332
1584
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1333
1585
  }
1334
- const auth = Array.from(AuthSet)[0];
1335
- const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, newSpec, this.options.allowMultipleParameters, auth);
1586
+ const authInfo = Array.from(authSet)[0];
1587
+ const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
1336
1588
  yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1337
1589
  result.warnings.push(...warnings);
1338
1590
  }
@@ -1364,12 +1616,13 @@ class SpecParser {
1364
1616
  if (this.apiMap !== undefined) {
1365
1617
  return this.apiMap;
1366
1618
  }
1367
- 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);
1368
1620
  this.apiMap = result;
1369
1621
  return result;
1370
1622
  }
1371
1623
  }
1372
1624
 
1625
+ exports.AdaptiveCardGenerator = AdaptiveCardGenerator;
1373
1626
  exports.ConstantString = ConstantString;
1374
1627
  exports.SpecParser = SpecParser;
1375
1628
  exports.SpecParserError = SpecParserError;