@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.
@@ -19,7 +19,7 @@ var ErrorType;
19
19
  ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
20
20
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
21
21
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
22
- ErrorType["MultipleAPIKeyNotSupported"] = "multiple-api-key-not-supported";
22
+ ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
23
23
  ErrorType["ListFailed"] = "list-failed";
24
24
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
25
25
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -27,6 +27,7 @@ var ErrorType;
27
27
  ErrorType["GenerateAdaptiveCardFailed"] = "generate-adaptive-card-failed";
28
28
  ErrorType["GenerateFailed"] = "generate-failed";
29
29
  ErrorType["ValidateFailed"] = "validate-failed";
30
+ ErrorType["GetSpecFailed"] = "get-spec-failed";
30
31
  ErrorType["Cancelled"] = "cancelled";
31
32
  ErrorType["Unknown"] = "unknown";
32
33
  })(ErrorType || (ErrorType = {}));
@@ -49,7 +50,13 @@ var ValidationStatus;
49
50
  ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
50
51
  ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
51
52
  ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
52
- })(ValidationStatus || (ValidationStatus = {}));
53
+ })(ValidationStatus || (ValidationStatus = {}));
54
+ var ProjectType;
55
+ (function (ProjectType) {
56
+ ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
57
+ ProjectType[ProjectType["SME"] = 1] = "SME";
58
+ ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
59
+ })(ProjectType || (ProjectType = {}));
53
60
 
54
61
  // Copyright (c) Microsoft Corporation.
55
62
  class ConstantString {
@@ -68,7 +75,8 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
68
75
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
69
76
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
70
77
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
71
- ConstantString.MultipleAPIKeyNotSupported = "Multiple API keys are not supported. Please make sure that all selected APIs use the same API key.";
78
+ ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
79
+ ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
72
80
  ConstantString.WrappedCardVersion = "devPreview";
73
81
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
74
82
  ConstantString.WrappedCardResponseLayout = "list";
@@ -80,6 +88,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
80
88
  ConstantString.TextBlockType = "TextBlock";
81
89
  ConstantString.ContainerType = "Container";
82
90
  ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
91
+ ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
83
92
  ConstantString.ResponseCodeFor20X = [
84
93
  "200",
85
94
  "201",
@@ -139,7 +148,8 @@ ConstantString.FullDescriptionMaxLens = 4000;
139
148
  ConstantString.CommandDescriptionMaxLens = 128;
140
149
  ConstantString.ParameterDescriptionMaxLens = 128;
141
150
  ConstantString.CommandTitleMaxLens = 32;
142
- ConstantString.ParameterTitleMaxLens = 32;
151
+ ConstantString.ParameterTitleMaxLens = 32;
152
+ ConstantString.SMERequiredParamsMaxNum = 5;
143
153
 
144
154
  // Copyright (c) Microsoft Corporation.
145
155
  class SpecParserError extends Error {
@@ -151,7 +161,18 @@ class SpecParserError extends Error {
151
161
 
152
162
  // Copyright (c) Microsoft Corporation.
153
163
  class Utils {
154
- static checkParameters(paramObject) {
164
+ static hasNestedObjectInSchema(schema) {
165
+ if (schema.type === "object") {
166
+ for (const property in schema.properties) {
167
+ const nestedSchema = schema.properties[property];
168
+ if (nestedSchema.type === "object") {
169
+ return true;
170
+ }
171
+ }
172
+ }
173
+ return false;
174
+ }
175
+ static checkParameters(paramObject, isCopilot) {
155
176
  const paramResult = {
156
177
  requiredNum: 0,
157
178
  optionalNum: 0,
@@ -163,7 +184,20 @@ class Utils {
163
184
  for (let i = 0; i < paramObject.length; i++) {
164
185
  const param = paramObject[i];
165
186
  const schema = param.schema;
187
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
188
+ paramResult.isValid = false;
189
+ continue;
190
+ }
166
191
  const isRequiredWithoutDefault = param.required && schema.default === undefined;
192
+ if (isCopilot) {
193
+ if (isRequiredWithoutDefault) {
194
+ paramResult.requiredNum = paramResult.requiredNum + 1;
195
+ }
196
+ else {
197
+ paramResult.optionalNum = paramResult.optionalNum + 1;
198
+ }
199
+ continue;
200
+ }
167
201
  if (param.in === "header" || param.in === "cookie") {
168
202
  if (isRequiredWithoutDefault) {
169
203
  paramResult.isValid = false;
@@ -190,7 +224,7 @@ class Utils {
190
224
  }
191
225
  return paramResult;
192
226
  }
193
- static checkPostBody(schema, isRequired = false) {
227
+ static checkPostBody(schema, isRequired = false, isCopilot = false) {
194
228
  var _a;
195
229
  const paramResult = {
196
230
  requiredNum: 0,
@@ -201,6 +235,10 @@ class Utils {
201
235
  return paramResult;
202
236
  }
203
237
  const isRequiredWithoutDefault = isRequired && schema.default === undefined;
238
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
239
+ paramResult.isValid = false;
240
+ return paramResult;
241
+ }
204
242
  if (schema.type === "string" ||
205
243
  schema.type === "integer" ||
206
244
  schema.type === "boolean" ||
@@ -219,19 +257,22 @@ class Utils {
219
257
  if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
220
258
  isRequired = true;
221
259
  }
222
- const result = Utils.checkPostBody(properties[property], isRequired);
260
+ const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
223
261
  paramResult.requiredNum += result.requiredNum;
224
262
  paramResult.optionalNum += result.optionalNum;
225
263
  paramResult.isValid = paramResult.isValid && result.isValid;
226
264
  }
227
265
  }
228
266
  else {
229
- if (isRequiredWithoutDefault) {
267
+ if (isRequiredWithoutDefault && !isCopilot) {
230
268
  paramResult.isValid = false;
231
269
  }
232
270
  }
233
271
  return paramResult;
234
272
  }
273
+ static containMultipleMediaTypes(bodyObject) {
274
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
275
+ }
235
276
  /**
236
277
  * Checks if the given API is supported.
237
278
  * @param {string} method - The HTTP method of the API.
@@ -246,32 +287,40 @@ class Utils {
246
287
  * 5. response body should be “application/json” and not empty, and response code should be 20X
247
288
  * 6. only support request body with “application/json” content type
248
289
  */
249
- static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
290
+ static isSupportedApi(method, path, spec, options) {
291
+ var _a;
250
292
  const pathObj = spec.paths[path];
251
293
  method = method.toLocaleLowerCase();
252
294
  if (pathObj) {
253
- if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
254
- pathObj[method]) {
295
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
255
296
  const securities = pathObj[method].security;
256
- const authArray = Utils.getAuthArray(securities, spec);
257
- if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
258
- return false;
297
+ const isTeamsAi = options.projectType === ProjectType.TeamsAi;
298
+ const isCopilot = options.projectType === ProjectType.Copilot;
299
+ // Teams AI project doesn't care about auth, it will use authProvider for user to implement
300
+ if (!isTeamsAi) {
301
+ const authArray = Utils.getAuthArray(securities, spec);
302
+ if (!Utils.isSupportedAuth(authArray, options)) {
303
+ return false;
304
+ }
259
305
  }
260
306
  const operationObject = pathObj[method];
261
- if (!allowMissingId && !operationObject.operationId) {
307
+ if (!options.allowMissingId && !operationObject.operationId) {
262
308
  return false;
263
309
  }
264
310
  const paramObject = operationObject.parameters;
265
311
  const requestBody = operationObject.requestBody;
266
312
  const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
267
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
268
- if (mediaTypesCount > 1) {
313
+ if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
269
314
  return false;
270
315
  }
271
- const responseJson = Utils.getResponseJson(operationObject);
316
+ const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
272
317
  if (Object.keys(responseJson).length === 0) {
273
318
  return false;
274
319
  }
320
+ // Teams AI project doesn't care about request parameters/body
321
+ if (isTeamsAi) {
322
+ return true;
323
+ }
275
324
  let requestBodyParamResult = {
276
325
  requiredNum: 0,
277
326
  optionalNum: 0,
@@ -279,18 +328,26 @@ class Utils {
279
328
  };
280
329
  if (requestJsonBody) {
281
330
  const requestBodySchema = requestJsonBody.schema;
282
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required);
331
+ if (isCopilot && requestBodySchema.type !== "object") {
332
+ return false;
333
+ }
334
+ requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
283
335
  }
284
336
  if (!requestBodyParamResult.isValid) {
285
337
  return false;
286
338
  }
287
- const paramResult = Utils.checkParameters(paramObject);
339
+ const paramResult = Utils.checkParameters(paramObject, isCopilot);
288
340
  if (!paramResult.isValid) {
289
341
  return false;
290
342
  }
343
+ // Copilot support arbitrary parameters
344
+ if (isCopilot) {
345
+ return true;
346
+ }
291
347
  if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
292
- if (allowMultipleParameters &&
293
- requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
348
+ if (options.allowMultipleParameters &&
349
+ requestBodyParamResult.requiredNum + paramResult.requiredNum <=
350
+ ConstantString.SMERequiredParamsMaxNum) {
294
351
  return true;
295
352
  }
296
353
  return false;
@@ -309,29 +366,31 @@ class Utils {
309
366
  }
310
367
  return false;
311
368
  }
312
- static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
369
+ static isSupportedAuth(authSchemaArray, options) {
313
370
  if (authSchemaArray.length === 0) {
314
371
  return true;
315
372
  }
316
- if (allowAPIKeyAuth || allowOauth2) {
373
+ if (options.allowAPIKeyAuth || options.allowOauth2) {
317
374
  // Currently we don't support multiple auth in one operation
318
375
  if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
319
376
  return false;
320
377
  }
321
378
  for (const auths of authSchemaArray) {
322
379
  if (auths.length === 1) {
323
- if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
380
+ if (!options.allowOauth2 &&
381
+ options.allowAPIKeyAuth &&
382
+ Utils.isAPIKeyAuth(auths[0].authSchema)) {
324
383
  return true;
325
384
  }
326
- else if (!allowAPIKeyAuth &&
327
- allowOauth2 &&
328
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
385
+ else if (!options.allowAPIKeyAuth &&
386
+ options.allowOauth2 &&
387
+ Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema)) {
329
388
  return true;
330
389
  }
331
- else if (allowAPIKeyAuth &&
332
- allowOauth2 &&
390
+ else if (options.allowAPIKeyAuth &&
391
+ options.allowOauth2 &&
333
392
  (Utils.isAPIKeyAuth(auths[0].authSchema) ||
334
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
393
+ Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema))) {
335
394
  return true;
336
395
  }
337
396
  }
@@ -342,10 +401,11 @@ class Utils {
342
401
  static isAPIKeyAuth(authSchema) {
343
402
  return authSchema.type === "apiKey";
344
403
  }
345
- static isBearerTokenAuth(authSchema) {
346
- return (authSchema.type === "oauth2" ||
347
- authSchema.type === "openIdConnect" ||
348
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
404
+ static isOAuthWithAuthCodeFlow(authSchema) {
405
+ if (authSchema.type === "oauth2" && authSchema.flows && authSchema.flows.authorizationCode) {
406
+ return true;
407
+ }
408
+ return false;
349
409
  }
350
410
  static getAuthArray(securities, spec) {
351
411
  var _a;
@@ -373,18 +433,19 @@ class Utils {
373
433
  static updateFirstLetter(str) {
374
434
  return str.charAt(0).toUpperCase() + str.slice(1);
375
435
  }
376
- static getResponseJson(operationObject) {
436
+ static getResponseJson(operationObject, isTeamsAiProject = false) {
377
437
  var _a, _b;
378
438
  let json = {};
379
439
  for (const code of ConstantString.ResponseCodeFor20X) {
380
440
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
381
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
382
- if (mediaTypesCount > 1) {
383
- return {};
384
- }
385
441
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
386
442
  json = responseObject.content["application/json"];
387
- break;
443
+ if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
444
+ json = {};
445
+ }
446
+ else {
447
+ break;
448
+ }
388
449
  }
389
450
  }
390
451
  return json;
@@ -458,7 +519,7 @@ class Utils {
458
519
  }
459
520
  return errors;
460
521
  }
461
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
522
+ static validateServer(spec, options) {
462
523
  const errors = [];
463
524
  let hasTopLevelServers = false;
464
525
  let hasPathLevelServers = false;
@@ -479,7 +540,7 @@ class Utils {
479
540
  }
480
541
  for (const method in methods) {
481
542
  const operationObject = methods[method];
482
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
543
+ if (Utils.isSupportedApi(method, path, spec, options)) {
483
544
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
484
545
  hasOperationLevelServers = true;
485
546
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -566,7 +627,7 @@ class Utils {
566
627
  param.value = schema.default;
567
628
  }
568
629
  }
569
- static parseApiInfo(operationItem, allowMultipleParameters) {
630
+ static parseApiInfo(operationItem, options) {
570
631
  var _a, _b;
571
632
  const requiredParams = [];
572
633
  const optionalParams = [];
@@ -580,7 +641,7 @@ class Utils {
580
641
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
581
642
  };
582
643
  const schema = param.schema;
583
- if (allowMultipleParameters && schema) {
644
+ if (options.allowMultipleParameters && schema) {
584
645
  Utils.updateParameterWithInputType(schema, parameter);
585
646
  }
586
647
  if (param.in !== "header" && param.in !== "cookie") {
@@ -598,7 +659,7 @@ class Utils {
598
659
  const requestJson = requestBody.content["application/json"];
599
660
  if (Object.keys(requestJson).length !== 0) {
600
661
  const schema = requestJson.schema;
601
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
662
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
602
663
  requiredParams.push(...requiredP);
603
664
  optionalParams.push(...optionalP);
604
665
  }
@@ -629,14 +690,13 @@ class Utils {
629
690
  }
630
691
  return [command, warning];
631
692
  }
632
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
693
+ static listSupportedAPIs(spec, options) {
633
694
  const paths = spec.paths;
634
695
  const result = {};
635
696
  for (const path in paths) {
636
697
  const methods = paths[path];
637
698
  for (const method in methods) {
638
- // For developer preview, only support GET operation with only 1 parameter without auth
639
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
699
+ if (Utils.isSupportedApi(method, path, spec, options)) {
640
700
  const operationObject = methods[method];
641
701
  result[`${method.toUpperCase()} ${path}`] = operationObject;
642
702
  }
@@ -644,7 +704,7 @@ class Utils {
644
704
  }
645
705
  return result;
646
706
  }
647
- static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
707
+ static validateSpec(spec, parser, isSwaggerFile, options) {
648
708
  const errors = [];
649
709
  const warnings = [];
650
710
  if (isSwaggerFile) {
@@ -654,7 +714,7 @@ class Utils {
654
714
  });
655
715
  }
656
716
  // Server validation
657
- const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
717
+ const serverErrors = Utils.validateServer(spec, options);
658
718
  errors.push(...serverErrors);
659
719
  // Remote reference not supported
660
720
  const refPaths = parser.$refs.paths();
@@ -667,7 +727,7 @@ class Utils {
667
727
  });
668
728
  }
669
729
  // No supported API
670
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
730
+ const apiMap = Utils.listSupportedAPIs(spec, options);
671
731
  if (Object.keys(apiMap).length === 0) {
672
732
  errors.push({
673
733
  type: ErrorType.NoSupportedApi,
@@ -723,14 +783,14 @@ class Utils {
723
783
 
724
784
  // Copyright (c) Microsoft Corporation.
725
785
  class SpecFilter {
726
- static specFilter(filter, unResolveSpec, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
786
+ static specFilter(filter, unResolveSpec, resolvedSpec, options) {
727
787
  try {
728
788
  const newSpec = Object.assign({}, unResolveSpec);
729
789
  const newPaths = {};
730
790
  for (const filterItem of filter) {
731
791
  const [method, path] = filterItem.split(" ");
732
792
  const methodName = method.toLowerCase();
733
- if (!Utils.isSupportedApi(methodName, path, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
793
+ if (!Utils.isSupportedApi(methodName, path, resolvedSpec, options)) {
734
794
  continue;
735
795
  }
736
796
  if (!newPaths[path]) {
@@ -756,46 +816,168 @@ class SpecFilter {
756
816
 
757
817
  // Copyright (c) Microsoft Corporation.
758
818
  class ManifestUpdater {
759
- static async updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, spec, allowMultipleParameters, auth) {
819
+ static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options) {
820
+ const manifest = await fs.readJSON(manifestPath);
821
+ const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
822
+ manifest.plugins = [
823
+ {
824
+ pluginFile: apiPluginRelativePath,
825
+ },
826
+ ];
827
+ ManifestUpdater.updateManifestDescription(manifest, spec);
828
+ const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
829
+ const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, options);
830
+ return [manifest, apiPlugin];
831
+ }
832
+ static updateManifestDescription(manifest, spec) {
760
833
  var _a, _b;
834
+ manifest.description = {
835
+ short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
836
+ 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),
837
+ };
838
+ }
839
+ static mapOpenAPISchemaToFuncParam(schema, method, pathUrl) {
840
+ let parameter;
841
+ if (schema.type === "string" ||
842
+ schema.type === "boolean" ||
843
+ schema.type === "integer" ||
844
+ schema.type === "number" ||
845
+ schema.type === "array") {
846
+ parameter = schema;
847
+ }
848
+ else {
849
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), ErrorType.UpdateManifestFailed);
850
+ }
851
+ return parameter;
852
+ }
853
+ static generatePluginManifestSchema(spec, specRelativePath, options) {
854
+ var _a, _b, _c;
855
+ const functions = [];
856
+ const functionNames = [];
857
+ const paths = spec.paths;
858
+ for (const pathUrl in paths) {
859
+ const pathItem = paths[pathUrl];
860
+ if (pathItem) {
861
+ const operations = pathItem;
862
+ for (const method in operations) {
863
+ if (options.allowMethods.includes(method)) {
864
+ const operationItem = operations[method];
865
+ if (operationItem) {
866
+ const operationId = operationItem.operationId;
867
+ const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
868
+ const paramObject = operationItem.parameters;
869
+ const requestBody = operationItem.requestBody;
870
+ const parameters = {
871
+ type: "object",
872
+ properties: {},
873
+ required: [],
874
+ };
875
+ if (paramObject) {
876
+ for (let i = 0; i < paramObject.length; i++) {
877
+ const param = paramObject[i];
878
+ const schema = param.schema;
879
+ parameters.properties[param.name] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
880
+ if (param.required) {
881
+ parameters.required.push(param.name);
882
+ }
883
+ if (!parameters.properties[param.name].description) {
884
+ parameters.properties[param.name].description = (_b = param.description) !== null && _b !== void 0 ? _b : "";
885
+ }
886
+ }
887
+ }
888
+ if (requestBody) {
889
+ const requestJsonBody = requestBody.content["application/json"];
890
+ const requestBodySchema = requestJsonBody.schema;
891
+ if (requestBodySchema.type === "object") {
892
+ if (requestBodySchema.required) {
893
+ parameters.required.push(...requestBodySchema.required);
894
+ }
895
+ for (const property in requestBodySchema.properties) {
896
+ const schema = requestBodySchema.properties[property];
897
+ parameters.properties[property] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
898
+ }
899
+ }
900
+ else {
901
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
902
+ }
903
+ }
904
+ const funcObj = {
905
+ name: operationId,
906
+ description: description,
907
+ parameters: parameters,
908
+ };
909
+ functions.push(funcObj);
910
+ functionNames.push(operationId);
911
+ }
912
+ }
913
+ }
914
+ }
915
+ }
916
+ const apiPlugin = {
917
+ schema_version: "v2",
918
+ name_for_human: spec.info.title,
919
+ description_for_human: (_c = spec.info.description) !== null && _c !== void 0 ? _c : "<Please add description of the plugin>",
920
+ functions: functions,
921
+ runtimes: [
922
+ {
923
+ type: "OpenApi",
924
+ auth: {
925
+ type: "none", // TODO, support auth in the future
926
+ },
927
+ spec: {
928
+ url: specRelativePath,
929
+ },
930
+ run_for_functions: functionNames,
931
+ },
932
+ ],
933
+ };
934
+ return apiPlugin;
935
+ }
936
+ static async updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
761
937
  try {
762
938
  const originalManifest = await fs.readJSON(manifestPath);
763
939
  const updatedPart = {};
764
- const [commands, warnings] = await ManifestUpdater.generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters);
765
- const composeExtension = {
766
- composeExtensionType: "apiBased",
767
- apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
768
- commands: commands,
769
- };
770
- if (auth) {
771
- if (Utils.isAPIKeyAuth(auth)) {
772
- auth = auth;
773
- const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${auth.name}_${ConstantString.RegistrationIdPostfix}`);
774
- composeExtension.authorization = {
775
- authType: "apiSecretServiceAuth",
776
- apiSecretServiceAuthConfiguration: {
777
- apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
778
- },
779
- };
780
- }
781
- else if (Utils.isBearerTokenAuth(auth)) {
782
- composeExtension.authorization = {
783
- authType: "microsoftEntra",
784
- microsoftEntraConfiguration: {
785
- supportsSingleSignOn: true,
786
- },
787
- };
788
- updatedPart.webApplicationInfo = {
789
- id: "${{AAD_APP_CLIENT_ID}}",
790
- resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
791
- };
940
+ updatedPart.composeExtensions = [];
941
+ let warnings = [];
942
+ if (options.projectType === ProjectType.SME) {
943
+ const updateResult = await ManifestUpdater.generateCommands(spec, manifestPath, options, adaptiveCardFolder);
944
+ const commands = updateResult[0];
945
+ warnings = updateResult[1];
946
+ const composeExtension = {
947
+ composeExtensionType: "apiBased",
948
+ apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
949
+ commands: commands,
950
+ };
951
+ if (authInfo) {
952
+ let auth = authInfo.authSchema;
953
+ if (Utils.isAPIKeyAuth(auth)) {
954
+ auth = auth;
955
+ const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
956
+ composeExtension.authorization = {
957
+ authType: "apiSecretServiceAuth",
958
+ apiSecretServiceAuthConfiguration: {
959
+ apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
960
+ },
961
+ };
962
+ }
963
+ else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
964
+ const safeOAuth2RegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.OAuthRegistrationIdPostFix}`);
965
+ composeExtension.authorization = {
966
+ authType: "oAuth2.0",
967
+ oAuthConfiguration: {
968
+ oauthConfigurationId: `\${{${safeOAuth2RegistrationId}}}`,
969
+ },
970
+ };
971
+ updatedPart.webApplicationInfo = {
972
+ id: "${{AAD_APP_CLIENT_ID}}",
973
+ resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
974
+ };
975
+ }
792
976
  }
977
+ updatedPart.composeExtensions = [composeExtension];
793
978
  }
794
- updatedPart.description = {
795
- short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
796
- 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),
797
- };
798
- updatedPart.composeExtensions = [composeExtension];
979
+ updatedPart.description = originalManifest.description;
980
+ ManifestUpdater.updateManifestDescription(updatedPart, spec);
799
981
  const updatedManifest = Object.assign(Object.assign({}, originalManifest), updatedPart);
800
982
  return [updatedManifest, warnings];
801
983
  }
@@ -803,7 +985,8 @@ class ManifestUpdater {
803
985
  throw new SpecParserError(err.toString(), ErrorType.UpdateManifestFailed);
804
986
  }
805
987
  }
806
- static async generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters) {
988
+ static async generateCommands(spec, manifestPath, options, adaptiveCardFolder) {
989
+ var _a;
807
990
  const paths = spec.paths;
808
991
  const commands = [];
809
992
  const warnings = [];
@@ -814,14 +997,16 @@ class ManifestUpdater {
814
997
  const operations = pathItem;
815
998
  // Currently only support GET and POST method
816
999
  for (const method in operations) {
817
- if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
1000
+ if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
818
1001
  const operationItem = operations[method];
819
1002
  if (operationItem) {
820
- const [command, warning] = Utils.parseApiInfo(operationItem, allowMultipleParameters);
821
- const adaptiveCardPath = path.join(adaptiveCardFolder, command.id + ".json");
822
- command.apiResponseRenderingTemplateFile = (await fs.pathExists(adaptiveCardPath))
823
- ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
824
- : "";
1003
+ const [command, warning] = Utils.parseApiInfo(operationItem, options);
1004
+ if (adaptiveCardFolder) {
1005
+ const adaptiveCardPath = path.join(adaptiveCardFolder, command.id + ".json");
1006
+ command.apiResponseRenderingTemplateFile = (await fs.pathExists(adaptiveCardPath))
1007
+ ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
1008
+ : "";
1009
+ }
825
1010
  if (warning) {
826
1011
  warnings.push(warning);
827
1012
  }
@@ -1106,6 +1291,8 @@ class SpecParser {
1106
1291
  allowAPIKeyAuth: false,
1107
1292
  allowMultipleParameters: false,
1108
1293
  allowOauth2: false,
1294
+ allowMethods: ["get", "post"],
1295
+ projectType: ProjectType.SME,
1109
1296
  };
1110
1297
  this.pathOrSpec = pathOrDoc;
1111
1298
  this.parser = new SwaggerParser();
@@ -1138,7 +1325,7 @@ class SpecParser {
1138
1325
  ],
1139
1326
  };
1140
1327
  }
1141
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1328
+ return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
1142
1329
  }
1143
1330
  catch (err) {
1144
1331
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -1200,48 +1387,105 @@ class SpecParser {
1200
1387
  throw new SpecParserError(err.toString(), ErrorType.ListFailed);
1201
1388
  }
1202
1389
  }
1390
+ /**
1391
+ * Generate specs according to the filters.
1392
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1393
+ */
1394
+ async getFilteredSpecs(filter, signal) {
1395
+ try {
1396
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1397
+ throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1398
+ }
1399
+ await this.loadSpec();
1400
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1401
+ throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1402
+ }
1403
+ const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options);
1404
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1405
+ throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1406
+ }
1407
+ const newSpec = (await this.parser.dereference(newUnResolvedSpec));
1408
+ return [newUnResolvedSpec, newSpec];
1409
+ }
1410
+ catch (err) {
1411
+ if (err instanceof SpecParserError) {
1412
+ throw err;
1413
+ }
1414
+ throw new SpecParserError(err.toString(), ErrorType.GetSpecFailed);
1415
+ }
1416
+ }
1203
1417
  /**
1204
1418
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1205
1419
  * @param manifestPath A file path of the Teams app manifest file to update.
1206
1420
  * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1207
1421
  * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1208
- * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
1422
+ * @param pluginFilePath File path of the api plugin file to generate.
1209
1423
  */
1210
- async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1424
+ async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
1211
1425
  const result = {
1212
1426
  allSuccess: true,
1213
1427
  warnings: [],
1214
1428
  };
1215
1429
  try {
1216
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1217
- throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1430
+ const newSpecs = await this.getFilteredSpecs(filter, signal);
1431
+ const newUnResolvedSpec = newSpecs[0];
1432
+ const newSpec = newSpecs[1];
1433
+ let resultStr;
1434
+ if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
1435
+ resultStr = jsyaml.dump(newUnResolvedSpec);
1218
1436
  }
1219
- await this.loadSpec();
1220
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1221
- throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1437
+ else {
1438
+ resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1222
1439
  }
1223
- const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1440
+ await fs.outputFile(outputSpecPath, resultStr);
1224
1441
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1225
1442
  throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1226
1443
  }
1227
- const newSpec = (await this.parser.dereference(newUnResolvedSpec));
1228
- const AuthSet = new Set();
1229
- let hasMultipleAPIKeyAuth = false;
1444
+ const [updatedManifest, apiPlugin] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options);
1445
+ await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1446
+ await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 2 });
1447
+ }
1448
+ catch (err) {
1449
+ if (err instanceof SpecParserError) {
1450
+ throw err;
1451
+ }
1452
+ throw new SpecParserError(err.toString(), ErrorType.GenerateFailed);
1453
+ }
1454
+ return result;
1455
+ }
1456
+ /**
1457
+ * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1458
+ * @param manifestPath A file path of the Teams app manifest file to update.
1459
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1460
+ * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1461
+ * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
1462
+ */
1463
+ async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1464
+ const result = {
1465
+ allSuccess: true,
1466
+ warnings: [],
1467
+ };
1468
+ try {
1469
+ const newSpecs = await this.getFilteredSpecs(filter, signal);
1470
+ const newUnResolvedSpec = newSpecs[0];
1471
+ const newSpec = newSpecs[1];
1472
+ const authSet = new Set();
1473
+ let hasMultipleAuth = false;
1230
1474
  for (const url in newSpec.paths) {
1231
1475
  for (const method in newSpec.paths[url]) {
1232
1476
  const operation = newSpec.paths[url][method];
1233
1477
  const authArray = Utils.getAuthArray(operation.security, newSpec);
1234
1478
  if (authArray && authArray.length > 0) {
1235
- AuthSet.add(authArray[0][0].authSchema);
1236
- if (AuthSet.size > 1) {
1237
- hasMultipleAPIKeyAuth = true;
1479
+ authSet.add(authArray[0][0]);
1480
+ if (authSet.size > 1) {
1481
+ hasMultipleAuth = true;
1238
1482
  break;
1239
1483
  }
1240
1484
  }
1241
1485
  }
1242
1486
  }
1243
- if (hasMultipleAPIKeyAuth) {
1244
- throw new SpecParserError(ConstantString.MultipleAPIKeyNotSupported, ErrorType.MultipleAPIKeyNotSupported);
1487
+ if (hasMultipleAuth && this.options.projectType !== ProjectType.TeamsAi) {
1488
+ throw new SpecParserError(ConstantString.MultipleAuthNotSupported, ErrorType.MultipleAuthNotSupported);
1245
1489
  }
1246
1490
  let resultStr;
1247
1491
  if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
@@ -1251,26 +1495,28 @@ class SpecParser {
1251
1495
  resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1252
1496
  }
1253
1497
  await fs.outputFile(outputSpecPath, resultStr);
1254
- for (const url in newSpec.paths) {
1255
- for (const method in newSpec.paths[url]) {
1256
- // paths object may contain description/summary, so we need to check if it is a operation object
1257
- if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
1258
- const operation = newSpec.paths[url][method];
1259
- try {
1260
- const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1261
- const fileName = path.join(adaptiveCardFolder, `${operation.operationId}.json`);
1262
- const wrappedCard = wrapAdaptiveCard(card, jsonPath);
1263
- await fs.outputJSON(fileName, wrappedCard, { spaces: 2 });
1264
- const dataFileName = path.join(adaptiveCardFolder, `${operation.operationId}.data.json`);
1265
- await fs.outputJSON(dataFileName, {}, { spaces: 2 });
1266
- }
1267
- catch (err) {
1268
- result.allSuccess = false;
1269
- result.warnings.push({
1270
- type: WarningType.GenerateCardFailed,
1271
- content: err.toString(),
1272
- data: operation.operationId,
1273
- });
1498
+ if (adaptiveCardFolder) {
1499
+ for (const url in newSpec.paths) {
1500
+ for (const method in newSpec.paths[url]) {
1501
+ // paths object may contain description/summary which is not a http method, so we need to check if it is a operation object
1502
+ if (this.options.allowMethods.includes(method)) {
1503
+ const operation = newSpec.paths[url][method];
1504
+ try {
1505
+ const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1506
+ const fileName = path.join(adaptiveCardFolder, `${operation.operationId}.json`);
1507
+ const wrappedCard = wrapAdaptiveCard(card, jsonPath);
1508
+ await fs.outputJSON(fileName, wrappedCard, { spaces: 2 });
1509
+ const dataFileName = path.join(adaptiveCardFolder, `${operation.operationId}.data.json`);
1510
+ await fs.outputJSON(dataFileName, {}, { spaces: 2 });
1511
+ }
1512
+ catch (err) {
1513
+ result.allSuccess = false;
1514
+ result.warnings.push({
1515
+ type: WarningType.GenerateCardFailed,
1516
+ content: err.toString(),
1517
+ data: operation.operationId,
1518
+ });
1519
+ }
1274
1520
  }
1275
1521
  }
1276
1522
  }
@@ -1278,8 +1524,8 @@ class SpecParser {
1278
1524
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1279
1525
  throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1280
1526
  }
1281
- const auth = Array.from(AuthSet)[0];
1282
- const [updatedManifest, warnings] = await ManifestUpdater.updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, newSpec, this.options.allowMultipleParameters, auth);
1527
+ const authInfo = Array.from(authSet)[0];
1528
+ const [updatedManifest, warnings] = await ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
1283
1529
  await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1284
1530
  result.warnings.push(...warnings);
1285
1531
  }
@@ -1308,11 +1554,11 @@ class SpecParser {
1308
1554
  if (this.apiMap !== undefined) {
1309
1555
  return this.apiMap;
1310
1556
  }
1311
- const result = Utils.listSupportedAPIs(spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1557
+ const result = Utils.listSupportedAPIs(spec, this.options);
1312
1558
  this.apiMap = result;
1313
1559
  return result;
1314
1560
  }
1315
1561
  }
1316
1562
 
1317
- export { ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
1563
+ export { AdaptiveCardGenerator, ConstantString, ErrorType, ProjectType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
1318
1564
  //# sourceMappingURL=index.esm2017.mjs.map