@microsoft/m365-spec-parser 0.1.1-alpha.cd2ba87f2.0 → 0.1.1-alpha.d1a09e202.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,20 @@ class Utils {
309
366
  }
310
367
  return false;
311
368
  }
312
- static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
313
- if (authSchemaArray.length === 0) {
369
+ static isSupportedAuth(authSchemeArray, options) {
370
+ if (authSchemeArray.length === 0) {
314
371
  return true;
315
372
  }
316
- if (allowAPIKeyAuth || allowOauth2) {
373
+ if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
317
374
  // Currently we don't support multiple auth in one operation
318
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
375
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
319
376
  return false;
320
377
  }
321
- for (const auths of authSchemaArray) {
378
+ for (const auths of authSchemeArray) {
322
379
  if (auths.length === 1) {
323
- if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
324
- return true;
325
- }
326
- else if (!allowAPIKeyAuth &&
327
- allowOauth2 &&
328
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
329
- return true;
330
- }
331
- else if (allowAPIKeyAuth &&
332
- allowOauth2 &&
333
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
334
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
380
+ if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
381
+ (options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
382
+ (options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
335
383
  return true;
336
384
  }
337
385
  }
@@ -339,13 +387,17 @@ class Utils {
339
387
  }
340
388
  return false;
341
389
  }
342
- static isAPIKeyAuth(authSchema) {
343
- return authSchema.type === "apiKey";
390
+ static isBearerTokenAuth(authScheme) {
391
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
344
392
  }
345
- static isBearerTokenAuth(authSchema) {
346
- return (authSchema.type === "oauth2" ||
347
- authSchema.type === "openIdConnect" ||
348
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
393
+ static isAPIKeyAuth(authScheme) {
394
+ return authScheme.type === "apiKey";
395
+ }
396
+ static isOAuthWithAuthCodeFlow(authScheme) {
397
+ if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
398
+ return true;
399
+ }
400
+ return false;
349
401
  }
350
402
  static getAuthArray(securities, spec) {
351
403
  var _a;
@@ -358,7 +410,7 @@ class Utils {
358
410
  for (const name in security) {
359
411
  const auth = securitySchemas[name];
360
412
  authArray.push({
361
- authSchema: auth,
413
+ authScheme: auth,
362
414
  name: name,
363
415
  });
364
416
  }
@@ -373,18 +425,19 @@ class Utils {
373
425
  static updateFirstLetter(str) {
374
426
  return str.charAt(0).toUpperCase() + str.slice(1);
375
427
  }
376
- static getResponseJson(operationObject) {
428
+ static getResponseJson(operationObject, isTeamsAiProject = false) {
377
429
  var _a, _b;
378
430
  let json = {};
379
431
  for (const code of ConstantString.ResponseCodeFor20X) {
380
432
  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
433
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
386
434
  json = responseObject.content["application/json"];
387
- break;
435
+ if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
436
+ json = {};
437
+ }
438
+ else {
439
+ break;
440
+ }
388
441
  }
389
442
  }
390
443
  return json;
@@ -458,7 +511,7 @@ class Utils {
458
511
  }
459
512
  return errors;
460
513
  }
461
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
514
+ static validateServer(spec, options) {
462
515
  const errors = [];
463
516
  let hasTopLevelServers = false;
464
517
  let hasPathLevelServers = false;
@@ -479,7 +532,7 @@ class Utils {
479
532
  }
480
533
  for (const method in methods) {
481
534
  const operationObject = methods[method];
482
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
535
+ if (Utils.isSupportedApi(method, path, spec, options)) {
483
536
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
484
537
  hasOperationLevelServers = true;
485
538
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -566,7 +619,7 @@ class Utils {
566
619
  param.value = schema.default;
567
620
  }
568
621
  }
569
- static parseApiInfo(operationItem, allowMultipleParameters) {
622
+ static parseApiInfo(operationItem, options) {
570
623
  var _a, _b;
571
624
  const requiredParams = [];
572
625
  const optionalParams = [];
@@ -580,7 +633,7 @@ class Utils {
580
633
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
581
634
  };
582
635
  const schema = param.schema;
583
- if (allowMultipleParameters && schema) {
636
+ if (options.allowMultipleParameters && schema) {
584
637
  Utils.updateParameterWithInputType(schema, parameter);
585
638
  }
586
639
  if (param.in !== "header" && param.in !== "cookie") {
@@ -598,7 +651,7 @@ class Utils {
598
651
  const requestJson = requestBody.content["application/json"];
599
652
  if (Object.keys(requestJson).length !== 0) {
600
653
  const schema = requestJson.schema;
601
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
654
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
602
655
  requiredParams.push(...requiredP);
603
656
  optionalParams.push(...optionalP);
604
657
  }
@@ -629,14 +682,13 @@ class Utils {
629
682
  }
630
683
  return [command, warning];
631
684
  }
632
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
685
+ static listSupportedAPIs(spec, options) {
633
686
  const paths = spec.paths;
634
687
  const result = {};
635
688
  for (const path in paths) {
636
689
  const methods = paths[path];
637
690
  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)) {
691
+ if (Utils.isSupportedApi(method, path, spec, options)) {
640
692
  const operationObject = methods[method];
641
693
  result[`${method.toUpperCase()} ${path}`] = operationObject;
642
694
  }
@@ -644,7 +696,7 @@ class Utils {
644
696
  }
645
697
  return result;
646
698
  }
647
- static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
699
+ static validateSpec(spec, parser, isSwaggerFile, options) {
648
700
  const errors = [];
649
701
  const warnings = [];
650
702
  if (isSwaggerFile) {
@@ -654,7 +706,7 @@ class Utils {
654
706
  });
655
707
  }
656
708
  // Server validation
657
- const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
709
+ const serverErrors = Utils.validateServer(spec, options);
658
710
  errors.push(...serverErrors);
659
711
  // Remote reference not supported
660
712
  const refPaths = parser.$refs.paths();
@@ -667,7 +719,7 @@ class Utils {
667
719
  });
668
720
  }
669
721
  // No supported API
670
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
722
+ const apiMap = Utils.listSupportedAPIs(spec, options);
671
723
  if (Object.keys(apiMap).length === 0) {
672
724
  errors.push({
673
725
  type: ErrorType.NoSupportedApi,
@@ -723,14 +775,14 @@ class Utils {
723
775
 
724
776
  // Copyright (c) Microsoft Corporation.
725
777
  class SpecFilter {
726
- static specFilter(filter, unResolveSpec, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
778
+ static specFilter(filter, unResolveSpec, resolvedSpec, options) {
727
779
  try {
728
780
  const newSpec = Object.assign({}, unResolveSpec);
729
781
  const newPaths = {};
730
782
  for (const filterItem of filter) {
731
783
  const [method, path] = filterItem.split(" ");
732
784
  const methodName = method.toLowerCase();
733
- if (!Utils.isSupportedApi(methodName, path, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
785
+ if (!Utils.isSupportedApi(methodName, path, resolvedSpec, options)) {
734
786
  continue;
735
787
  }
736
788
  if (!newPaths[path]) {
@@ -756,46 +808,167 @@ class SpecFilter {
756
808
 
757
809
  // Copyright (c) Microsoft Corporation.
758
810
  class ManifestUpdater {
759
- static async updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, spec, allowMultipleParameters, auth) {
811
+ static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options) {
812
+ const manifest = await fs.readJSON(manifestPath);
813
+ const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
814
+ manifest.plugins = [
815
+ {
816
+ pluginFile: apiPluginRelativePath,
817
+ },
818
+ ];
819
+ ManifestUpdater.updateManifestDescription(manifest, spec);
820
+ const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
821
+ const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, options);
822
+ return [manifest, apiPlugin];
823
+ }
824
+ static updateManifestDescription(manifest, spec) {
760
825
  var _a, _b;
826
+ manifest.description = {
827
+ short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
828
+ 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),
829
+ };
830
+ }
831
+ static mapOpenAPISchemaToFuncParam(schema, method, pathUrl) {
832
+ let parameter;
833
+ if (schema.type === "string" ||
834
+ schema.type === "boolean" ||
835
+ schema.type === "integer" ||
836
+ schema.type === "number" ||
837
+ schema.type === "array") {
838
+ parameter = schema;
839
+ }
840
+ else {
841
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), ErrorType.UpdateManifestFailed);
842
+ }
843
+ return parameter;
844
+ }
845
+ static generatePluginManifestSchema(spec, specRelativePath, options) {
846
+ var _a, _b, _c;
847
+ const functions = [];
848
+ const functionNames = [];
849
+ const paths = spec.paths;
850
+ for (const pathUrl in paths) {
851
+ const pathItem = paths[pathUrl];
852
+ if (pathItem) {
853
+ const operations = pathItem;
854
+ for (const method in operations) {
855
+ if (options.allowMethods.includes(method)) {
856
+ const operationItem = operations[method];
857
+ if (operationItem) {
858
+ const operationId = operationItem.operationId;
859
+ const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
860
+ const paramObject = operationItem.parameters;
861
+ const requestBody = operationItem.requestBody;
862
+ const parameters = {
863
+ type: "object",
864
+ properties: {},
865
+ required: [],
866
+ };
867
+ if (paramObject) {
868
+ for (let i = 0; i < paramObject.length; i++) {
869
+ const param = paramObject[i];
870
+ const schema = param.schema;
871
+ parameters.properties[param.name] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
872
+ if (param.required) {
873
+ parameters.required.push(param.name);
874
+ }
875
+ if (!parameters.properties[param.name].description) {
876
+ parameters.properties[param.name].description = (_b = param.description) !== null && _b !== void 0 ? _b : "";
877
+ }
878
+ }
879
+ }
880
+ if (requestBody) {
881
+ const requestJsonBody = requestBody.content["application/json"];
882
+ const requestBodySchema = requestJsonBody.schema;
883
+ if (requestBodySchema.type === "object") {
884
+ if (requestBodySchema.required) {
885
+ parameters.required.push(...requestBodySchema.required);
886
+ }
887
+ for (const property in requestBodySchema.properties) {
888
+ const schema = requestBodySchema.properties[property];
889
+ parameters.properties[property] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
890
+ }
891
+ }
892
+ else {
893
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
894
+ }
895
+ }
896
+ const funcObj = {
897
+ name: operationId,
898
+ description: description,
899
+ parameters: parameters,
900
+ };
901
+ functions.push(funcObj);
902
+ functionNames.push(operationId);
903
+ }
904
+ }
905
+ }
906
+ }
907
+ }
908
+ const apiPlugin = {
909
+ schema_version: "v2",
910
+ name_for_human: spec.info.title,
911
+ description_for_human: (_c = spec.info.description) !== null && _c !== void 0 ? _c : "<Please add description of the plugin>",
912
+ functions: functions,
913
+ runtimes: [
914
+ {
915
+ type: "OpenApi",
916
+ auth: {
917
+ type: "none", // TODO, support auth in the future
918
+ },
919
+ spec: {
920
+ url: specRelativePath,
921
+ },
922
+ run_for_functions: functionNames,
923
+ },
924
+ ],
925
+ };
926
+ return apiPlugin;
927
+ }
928
+ static async updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
761
929
  try {
762
930
  const originalManifest = await fs.readJSON(manifestPath);
763
931
  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
- };
932
+ updatedPart.composeExtensions = [];
933
+ let warnings = [];
934
+ if (options.projectType === ProjectType.SME) {
935
+ const updateResult = await ManifestUpdater.generateCommands(spec, manifestPath, options, adaptiveCardFolder);
936
+ const commands = updateResult[0];
937
+ warnings = updateResult[1];
938
+ const composeExtension = {
939
+ composeExtensionType: "apiBased",
940
+ apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
941
+ commands: commands,
942
+ };
943
+ if (authInfo) {
944
+ const auth = authInfo.authScheme;
945
+ if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
946
+ const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
947
+ composeExtension.authorization = {
948
+ authType: "apiSecretServiceAuth",
949
+ apiSecretServiceAuthConfiguration: {
950
+ apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
951
+ },
952
+ };
953
+ }
954
+ else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
955
+ const safeOAuth2RegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.OAuthRegistrationIdPostFix}`);
956
+ composeExtension.authorization = {
957
+ authType: "oAuth2.0",
958
+ oAuthConfiguration: {
959
+ oauthConfigurationId: `\${{${safeOAuth2RegistrationId}}}`,
960
+ },
961
+ };
962
+ updatedPart.webApplicationInfo = {
963
+ id: "${{AAD_APP_CLIENT_ID}}",
964
+ resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
965
+ };
966
+ }
792
967
  }
968
+ updatedPart.composeExtensions = [composeExtension];
793
969
  }
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];
970
+ updatedPart.description = originalManifest.description;
971
+ ManifestUpdater.updateManifestDescription(updatedPart, spec);
799
972
  const updatedManifest = Object.assign(Object.assign({}, originalManifest), updatedPart);
800
973
  return [updatedManifest, warnings];
801
974
  }
@@ -803,7 +976,8 @@ class ManifestUpdater {
803
976
  throw new SpecParserError(err.toString(), ErrorType.UpdateManifestFailed);
804
977
  }
805
978
  }
806
- static async generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters) {
979
+ static async generateCommands(spec, manifestPath, options, adaptiveCardFolder) {
980
+ var _a;
807
981
  const paths = spec.paths;
808
982
  const commands = [];
809
983
  const warnings = [];
@@ -814,14 +988,16 @@ class ManifestUpdater {
814
988
  const operations = pathItem;
815
989
  // Currently only support GET and POST method
816
990
  for (const method in operations) {
817
- if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
991
+ if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
818
992
  const operationItem = operations[method];
819
993
  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
- : "";
994
+ const [command, warning] = Utils.parseApiInfo(operationItem, options);
995
+ if (adaptiveCardFolder) {
996
+ const adaptiveCardPath = path.join(adaptiveCardFolder, command.id + ".json");
997
+ command.apiResponseRenderingTemplateFile = (await fs.pathExists(adaptiveCardPath))
998
+ ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
999
+ : "";
1000
+ }
825
1001
  if (warning) {
826
1002
  warnings.push(warning);
827
1003
  }
@@ -1104,8 +1280,11 @@ class SpecParser {
1104
1280
  allowMissingId: true,
1105
1281
  allowSwagger: true,
1106
1282
  allowAPIKeyAuth: false,
1283
+ allowBearerTokenAuth: false,
1107
1284
  allowMultipleParameters: false,
1108
1285
  allowOauth2: false,
1286
+ allowMethods: ["get", "post"],
1287
+ projectType: ProjectType.SME,
1109
1288
  };
1110
1289
  this.pathOrSpec = pathOrDoc;
1111
1290
  this.parser = new SwaggerParser();
@@ -1138,7 +1317,7 @@ class SpecParser {
1138
1317
  ],
1139
1318
  };
1140
1319
  }
1141
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1320
+ return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
1142
1321
  }
1143
1322
  catch (err) {
1144
1323
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -1184,7 +1363,7 @@ class SpecParser {
1184
1363
  const authArray = Utils.getAuthArray(operation.security, spec);
1185
1364
  for (const auths of authArray) {
1186
1365
  if (auths.length === 1) {
1187
- apiResult.auth = auths[0].authSchema;
1366
+ apiResult.auth = auths[0].authScheme;
1188
1367
  break;
1189
1368
  }
1190
1369
  }
@@ -1200,48 +1379,105 @@ class SpecParser {
1200
1379
  throw new SpecParserError(err.toString(), ErrorType.ListFailed);
1201
1380
  }
1202
1381
  }
1382
+ /**
1383
+ * Generate specs according to the filters.
1384
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1385
+ */
1386
+ async getFilteredSpecs(filter, signal) {
1387
+ try {
1388
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1389
+ throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1390
+ }
1391
+ await this.loadSpec();
1392
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1393
+ throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1394
+ }
1395
+ const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options);
1396
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1397
+ throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1398
+ }
1399
+ const newSpec = (await this.parser.dereference(newUnResolvedSpec));
1400
+ return [newUnResolvedSpec, newSpec];
1401
+ }
1402
+ catch (err) {
1403
+ if (err instanceof SpecParserError) {
1404
+ throw err;
1405
+ }
1406
+ throw new SpecParserError(err.toString(), ErrorType.GetSpecFailed);
1407
+ }
1408
+ }
1203
1409
  /**
1204
1410
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1205
1411
  * @param manifestPath A file path of the Teams app manifest file to update.
1206
1412
  * @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
1413
  * @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.
1414
+ * @param pluginFilePath File path of the api plugin file to generate.
1209
1415
  */
1210
- async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1416
+ async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
1211
1417
  const result = {
1212
1418
  allSuccess: true,
1213
1419
  warnings: [],
1214
1420
  };
1215
1421
  try {
1216
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1217
- throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1422
+ const newSpecs = await this.getFilteredSpecs(filter, signal);
1423
+ const newUnResolvedSpec = newSpecs[0];
1424
+ const newSpec = newSpecs[1];
1425
+ let resultStr;
1426
+ if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
1427
+ resultStr = jsyaml.dump(newUnResolvedSpec);
1218
1428
  }
1219
- await this.loadSpec();
1220
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1221
- throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1429
+ else {
1430
+ resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1222
1431
  }
1223
- const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1432
+ await fs.outputFile(outputSpecPath, resultStr);
1224
1433
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1225
1434
  throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1226
1435
  }
1227
- const newSpec = (await this.parser.dereference(newUnResolvedSpec));
1228
- const AuthSet = new Set();
1229
- let hasMultipleAPIKeyAuth = false;
1436
+ const [updatedManifest, apiPlugin] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options);
1437
+ await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1438
+ await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 2 });
1439
+ }
1440
+ catch (err) {
1441
+ if (err instanceof SpecParserError) {
1442
+ throw err;
1443
+ }
1444
+ throw new SpecParserError(err.toString(), ErrorType.GenerateFailed);
1445
+ }
1446
+ return result;
1447
+ }
1448
+ /**
1449
+ * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1450
+ * @param manifestPath A file path of the Teams app manifest file to update.
1451
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1452
+ * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1453
+ * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
1454
+ */
1455
+ async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1456
+ const result = {
1457
+ allSuccess: true,
1458
+ warnings: [],
1459
+ };
1460
+ try {
1461
+ const newSpecs = await this.getFilteredSpecs(filter, signal);
1462
+ const newUnResolvedSpec = newSpecs[0];
1463
+ const newSpec = newSpecs[1];
1464
+ const authSet = new Set();
1465
+ let hasMultipleAuth = false;
1230
1466
  for (const url in newSpec.paths) {
1231
1467
  for (const method in newSpec.paths[url]) {
1232
1468
  const operation = newSpec.paths[url][method];
1233
1469
  const authArray = Utils.getAuthArray(operation.security, newSpec);
1234
1470
  if (authArray && authArray.length > 0) {
1235
- AuthSet.add(authArray[0][0].authSchema);
1236
- if (AuthSet.size > 1) {
1237
- hasMultipleAPIKeyAuth = true;
1471
+ authSet.add(authArray[0][0]);
1472
+ if (authSet.size > 1) {
1473
+ hasMultipleAuth = true;
1238
1474
  break;
1239
1475
  }
1240
1476
  }
1241
1477
  }
1242
1478
  }
1243
- if (hasMultipleAPIKeyAuth) {
1244
- throw new SpecParserError(ConstantString.MultipleAPIKeyNotSupported, ErrorType.MultipleAPIKeyNotSupported);
1479
+ if (hasMultipleAuth && this.options.projectType !== ProjectType.TeamsAi) {
1480
+ throw new SpecParserError(ConstantString.MultipleAuthNotSupported, ErrorType.MultipleAuthNotSupported);
1245
1481
  }
1246
1482
  let resultStr;
1247
1483
  if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
@@ -1251,26 +1487,28 @@ class SpecParser {
1251
1487
  resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1252
1488
  }
1253
1489
  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
- });
1490
+ if (adaptiveCardFolder) {
1491
+ for (const url in newSpec.paths) {
1492
+ for (const method in newSpec.paths[url]) {
1493
+ // paths object may contain description/summary which is not a http method, so we need to check if it is a operation object
1494
+ if (this.options.allowMethods.includes(method)) {
1495
+ const operation = newSpec.paths[url][method];
1496
+ try {
1497
+ const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1498
+ const fileName = path.join(adaptiveCardFolder, `${operation.operationId}.json`);
1499
+ const wrappedCard = wrapAdaptiveCard(card, jsonPath);
1500
+ await fs.outputJSON(fileName, wrappedCard, { spaces: 2 });
1501
+ const dataFileName = path.join(adaptiveCardFolder, `${operation.operationId}.data.json`);
1502
+ await fs.outputJSON(dataFileName, {}, { spaces: 2 });
1503
+ }
1504
+ catch (err) {
1505
+ result.allSuccess = false;
1506
+ result.warnings.push({
1507
+ type: WarningType.GenerateCardFailed,
1508
+ content: err.toString(),
1509
+ data: operation.operationId,
1510
+ });
1511
+ }
1274
1512
  }
1275
1513
  }
1276
1514
  }
@@ -1278,8 +1516,8 @@ class SpecParser {
1278
1516
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1279
1517
  throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1280
1518
  }
1281
- const auth = Array.from(AuthSet)[0];
1282
- const [updatedManifest, warnings] = await ManifestUpdater.updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, newSpec, this.options.allowMultipleParameters, auth);
1519
+ const authInfo = Array.from(authSet)[0];
1520
+ const [updatedManifest, warnings] = await ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
1283
1521
  await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1284
1522
  result.warnings.push(...warnings);
1285
1523
  }
@@ -1308,11 +1546,11 @@ class SpecParser {
1308
1546
  if (this.apiMap !== undefined) {
1309
1547
  return this.apiMap;
1310
1548
  }
1311
- const result = Utils.listSupportedAPIs(spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1549
+ const result = Utils.listSupportedAPIs(spec, this.options);
1312
1550
  this.apiMap = result;
1313
1551
  return result;
1314
1552
  }
1315
1553
  }
1316
1554
 
1317
- export { ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
1555
+ export { AdaptiveCardGenerator, ConstantString, ErrorType, ProjectType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
1318
1556
  //# sourceMappingURL=index.esm2017.mjs.map