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